{"openapi":"3.1.0","info":{"description":"The Folio API is JSON over HTTPS. A church API key picks the church, so there is no church in the URL. Every route lives under `/v1`.\n\n**Envelope.** Success is `{status, message, data, meta}`. Failure is `{status, message, error{code, status, request_id}}` with a closed list of snake_case codes. Quote `request_id` when you contact support.\n\n**Keys.** `folio_live_` keys work on real churches and `folio_test_` keys work on sandbox churches. Partner keys manage customer churches and can act for one by sending `X-Folio-Church`. Booth devices use `folio_booth_` keys.\n\n**Retries.** Send `Idempotency-Key` on any `POST`, `PUT`, `PATCH` or `DELETE`. Back off on `429` and `503`.\n\n**Scripture.** Verses are the King James Version only.\n\n**Review first.** Notes and outputs reach keys only after a person (or the church's automatic approval) has published them.\n\nGuides, quickstart and the webhook event catalogue: https://folio.candensa.com/docs\n\nAPI reference: https://folio.candensa.com/developers","summary":"Add teachings, read transcripts and notes, ask from what the church has approved, and receive webhooks.","termsOfService":"https://folio.candensa.com/terms","title":"Folio API","version":"0.0.0-dev","x-api-id":"folio-v1"},"externalDocs":{"description":"Guides, quickstart and webhook event catalogue","url":"https://folio.candensa.com/docs"},"servers":[{"description":"Folio API. Real churches use folio_live_ keys and sandbox churches use folio_test_ keys on this host.","url":"https://folio-app.candensa.com"}],"tags":[{"description":"Add recordings, watch them process and read the transcript. A teaching is one sermon or talk.","name":"Teachings"},{"description":"The notes Folio writes from a transcript. Keys read published notes only.","name":"Notes"},{"description":"Devotionals, blog posts, newsletters and study guides written from a note. Keys read published outputs only.","name":"Outputs"},{"description":"Conversations answered from the church's approved teaching, with citations.","name":"Ask"},{"description":"An OpenAI-compatible endpoint answered from the church's own teaching.","name":"Chat completions"},{"description":"King James Version text, with how often the church has taught each passage.","name":"Scripture"},{"description":"The church's plan, allowances and usage this cycle.","name":"Billing and usage"},{"description":"People who subscribed to the church's updates.","name":"Audience"},{"description":"Crisis alerts that need a person.","name":"Care"},{"description":"Links between churches in a network.","name":"Networks"},{"description":"Register https endpoints, rotate their signing secret, send a test event and read deliveries.","name":"Webhook endpoints"},{"description":"The events Folio sends. Each is a signed POST to your endpoint.","name":"Webhook events"},{"description":"Provision customer churches, including free sandbox churches, and mint scoped keys for them.","name":"Partners"},{"description":"Pairing, commands, updates and uploads for Folio Live on a booth machine.","name":"Booth devices"},{"description":"Sync the booth's songs, themes and service plans with the cloud.","name":"Booth library"},{"description":"Published notes, verses and series for a church, readable without a key.","name":"Published content"},{"description":"Ask on a church's public page.","name":"Public Ask"},{"description":"The embeddable Ask widget, identified by a site key and the calling origin.","name":"Widget"},{"description":"Live status and captions for a church that is streaming.","name":"Live"},{"description":"Subscribe an email address to a church's updates.","name":"Subscribe"},{"description":"The plan catalogue, the webhook event catalogue and service status.","name":"Plans and status"}],"x-tagGroups":[{"name":"Church API","tags":["Teachings","Notes","Outputs","Ask","Chat completions","Scripture","Billing and usage","Audience","Care","Networks"]},{"name":"Webhooks","tags":["Webhook endpoints","Webhook events"]},{"name":"Partners","tags":["Partners"]},{"name":"Booth devices","tags":["Booth devices","Booth library"]},{"name":"Public, no key","tags":["Published content","Public Ask","Widget","Live","Subscribe","Plans and status"]}],"security":[{"bearerAuth":[]}],"paths":{"/v1/billing":{"get":{"description":"Returns the church's standing, plan, what the plan allows (`entitlements`) and how much has been used this billing cycle (`usage`). Use it to show remaining allowance in your own screens, or to find out why a call answered `quota_exceeded`. Partner keys read a customer church by sending `X-Folio-Church`.\n\n**Auth.** A church API key. Needs the `billing:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetBilling","parameters":[{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"billing","data":{"object":"billing","standing":{"state":"active","reason":""},"plan":null,"entitlements":[],"usage":[],"cycle":{"start":"2026-11-01T00:00:00Z","end":"2026-12-01T00:00:00Z"}}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/BillingWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Read the plan and usage.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["billing:read"]}],"summary":"Read the plan and usage","tags":["Billing and usage"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/billing\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/billing`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/billing\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/billing\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["billing:read"]}},"/v1/billing/plans":{"get":{"description":"Lists the plans the church can choose, with prices per interval and currency and the allowances each plan carries. Prices change; read them from here or from `GET /v1/public/plans` instead of copying them.\n\n**Auth.** A church API key. Needs the `billing:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetBillingPlans","parameters":[{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"plans","data":[],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/PlanCatalogueWire"},"type":"array"},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/ListMeta"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. List plans.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["billing:read"]}],"summary":"List plans","tags":["Billing and usage"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/billing/plans\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/billing/plans`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/billing/plans\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/billing/plans\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["billing:read"]}},"/v1/care/alerts":{"get":{"description":"Lists care alerts raised when someone asked a question that needs a person. Treat the content as pastoral and private. `urgency` tells you how fast to respond; the details stay in the console.\n\n**Auth.** A church API key. Needs the `care:handle` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListCareAlerts","parameters":[{"description":"Items per page.","explode":false,"in":"query","name":"limit","schema":{"default":50,"description":"Items per page.","format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from meta.next_cursor of the previous page.","explode":false,"in":"query","name":"cursor","schema":{"description":"Opaque cursor from meta.next_cursor of the previous page.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"care_alerts","data":[{"id":"car_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"care_alert","status":"open","category":"crisis","urgency":"high"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyMachineCareAlertWire"}}},"description":"Success. List crisis alerts.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["care:handle"]}],"summary":"List crisis alerts","tags":["Care"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/care/alerts\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/care/alerts`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/care/alerts\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/care/alerts\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["care:handle"]}},"/v1/chat/completions":{"post":{"description":"An OpenAI-compatible chat completion answered from the church's own teaching, so tools that speak that format can point at Folio. The last `user` message is the question; `model` is accepted and ignored and the response reports `folio`.\n\nPass the returned `id`'s conversation as `conversation_id` to continue a thread. The request waits up to 55 seconds for the answer and answers 504 if it is slower. Streaming is not supported. `usage` is always zero. Errors use the Folio error envelope, not OpenAI's.\n\n**Auth.** A church API key. Needs the `ask:create` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Plan.** Needs the API and Ask features. A new conversation counts against the Ask allowance (402 `quota_exceeded`). Sandbox churches stop at their test AI budget.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"createChatCompletion","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"messages":[{"role":"user","content":"What did Sunday say about forgiveness?"}]}}},"schema":{"$ref":"#/components/schemas/ChatCompletionInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"ok","data":{"id":"chatcmpl-conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"chat.completion","created":1793541609,"model":"folio","choices":[{"index":0,"message":{"role":"assistant","content":"Forgiveness is a decision to release a debt, as God released ours. [1]"},"finish_reason":"stop"}],"usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0}}}}},"schema":{"$ref":"#/components/schemas/ChatCompletion"}}},"description":"Success. Create a chat completion.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"402":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This church has used its Ask allowance for this month.","error":{"code":"quota_exceeded","status":402,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The Ask allowance or the AI budget is used up."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"504":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"The answer is taking too long.","error":{"code":"unavailable","status":504,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The answer took longer than 55 seconds. Read the conversation later."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["ask:create"]}],"summary":"Create a chat completion","tags":["Chat completions"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/chat/completions\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: completion-1\" \\\n  -d '{\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"What did Sunday say about forgiveness?\"\n    }\n  ]\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/chat/completions`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"completion-1\",\n  },\n  body: JSON.stringify({\n    \"messages\": [\n      {\n        \"role\": \"user\",\n        \"content\": \"What did Sunday say about forgiveness?\"\n      }\n    ]\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/chat/completions\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n        \"Idempotency-Key\": \"completion-1\",\n    },\n    json={\n        \"messages\": [\n            {\n                \"role\": \"user\",\n                \"content\": \"What did Sunday say about forgiveness?\",\n            },\n        ],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"What did Sunday say about forgiveness?\"\n    }\n  ]\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/chat/completions\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"completion-1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the API and Ask features. A new conversation counts against the Ask allowance (402 `quota_exceeded`). Sandbox churches stop at their test AI budget.","x-rate-limited":true,"x-required-scopes":["ask:create"]}},"/v1/conversations":{"get":{"description":"Lists conversations started with this church's keys, most recently updated first. Messages are not included; read one conversation to get them.\n\n**Auth.** A church API key. Needs the `ask:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListConversations","parameters":[{"description":"How many items to return, from 1 to 100.","example":"20","explode":false,"in":"query","name":"limit","schema":{"format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"The opaque meta.next_cursor from the previous page.","explode":false,"in":"query","name":"cursor","schema":{"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"conversations","data":[{"id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"conversation","title":"What did we teach about forgiveness?","scope":{"kind":"org","library":"own"},"surface":"machine","audience":"private","message_count":2,"mine":false,"created_at":"2026-11-01T14:00:00Z","updated_at":"2026-11-01T14:00:09Z","messages":[]}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ConversationWire"},"type":"array"},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/ListMeta"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. List conversations.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["ask:read"]}],"summary":"List conversations","tags":["Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/conversations?limit=20\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/conversations?limit=20`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/conversations?limit=20\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/conversations?limit=20\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["ask:read"]},"post":{"description":"Starts a conversation and, when you send `input`, asks the first question. Answers are written from the church's own approved teaching and carry numbered sources.\n\nThe answer is asynchronous. The response holds the question and an answer with `kind` `pending`. Poll `GET /v1/conversations/{conversation}` until the answer's `kind` is no longer `pending`, or ask with `stream` on the messages route to receive it as server-sent events. Possible final kinds: `answer`, `not_covered` (the church has not taught on it), `stopped`, `unavailable`, and a few conversational kinds such as `greeting` and `offtopic`.\n\n`scope` narrows what the answer may draw on. Leave it out for the whole church (`{\"kind\":\"org\"}`).\n\n**Auth.** A church API key. Needs the `ask:create` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Plan.** Needs the API and Ask features. A new question counts against the plan's Ask allowance: 402 `quota_exceeded` when it is used up, and 402 `ai_budget_exhausted` when the monthly AI budget is.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineCreateConversation","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"title":"Forgiveness","input":"What did we teach about forgiveness?","scope":{"kind":"org","library":"own"}}}},"schema":{"$ref":"#/components/schemas/MachineCreateConversationInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"turn created","data":{"conversation":{"id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"conversation","title":"Forgiveness","scope":{"kind":"org","library":"own"},"surface":"machine","audience":"private","message_count":2,"mine":false,"created_at":"2026-11-01T14:00:00Z","updated_at":"2026-11-01T14:00:00Z","messages":[]},"turn":{"question":{"id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"message","role":"user","kind":"question","text":"What did we teach about forgiveness?","blocks":[],"follow_ups":[],"sources":[],"standing":[],"next_steps":[],"shareable":false,"created_at":"2026-11-01T14:00:00Z"},"answer":{"id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"message","role":"assistant","kind":"pending","blocks":[],"follow_ups":[],"sources":[],"standing":[],"next_steps":[],"shareable":false,"created_at":"2026-11-01T14:00:00Z"}}}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/AskWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Start a conversation.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"402":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This church has used its Ask allowance for this month.","error":{"code":"quota_exceeded","status":402,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The Ask allowance or the AI budget is used up."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That conversation scope is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The scope or a field is not valid."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["ask:create"]}],"summary":"Start a conversation","tags":["Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/conversations\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: faq-forgiveness-1\" \\\n  -d '{\n  \"title\": \"Forgiveness\",\n  \"input\": \"What did we teach about forgiveness?\",\n  \"scope\": {\n    \"kind\": \"org\",\n    \"library\": \"own\"\n  }\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/conversations`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"faq-forgiveness-1\",\n  },\n  body: JSON.stringify({\n    \"title\": \"Forgiveness\",\n    \"input\": \"What did we teach about forgiveness?\",\n    \"scope\": {\n      \"kind\": \"org\",\n      \"library\": \"own\"\n    }\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/conversations\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n        \"Idempotency-Key\": \"faq-forgiveness-1\",\n    },\n    json={\n        \"title\": \"Forgiveness\",\n        \"input\": \"What did we teach about forgiveness?\",\n        \"scope\": {\n            \"kind\": \"org\",\n            \"library\": \"own\",\n        },\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"title\": \"Forgiveness\",\n  \"input\": \"What did we teach about forgiveness?\",\n  \"scope\": {\n    \"kind\": \"org\",\n    \"library\": \"own\"\n  }\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/conversations\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"faq-forgiveness-1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the API and Ask features. A new question counts against the plan's Ask allowance: 402 `quota_exceeded` when it is used up, and 402 `ai_budget_exhausted` when the monthly AI budget is.","x-rate-limited":true,"x-required-scopes":["ask:create"]}},"/v1/conversations/{conversation}":{"get":{"description":"Returns a conversation with all its messages. Poll this after asking until the last message's `kind` is not `pending`. A finished answer has `short_answer`, `blocks` (each citing `source_refs`), `sources` (numbered, with speaker, date and a time-coded excerpt), `standing` (whether a source teaching has since been superseded or retracted) and `follow_ups`.\n\n**Auth.** A church API key. Needs the `ask:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetConversation","parameters":[{"description":"The conversation id, such as conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"conversation","required":true,"schema":{"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"conversation","data":{"id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"conversation","title":"Forgiveness","scope":{"kind":"org","library":"own"},"surface":"machine","audience":"private","message_count":2,"mine":false,"created_at":"2026-11-01T14:00:00Z","updated_at":"2026-11-01T14:00:09Z","messages":[{"id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"message","role":"user","kind":"question","text":"What did we teach about forgiveness?","blocks":[],"follow_ups":[],"sources":[],"standing":[],"next_steps":[],"shareable":false,"created_at":"2026-11-01T14:00:00Z"},{"id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"message","role":"assistant","kind":"answer","short_answer":"Forgiveness is a decision to release a debt, as God released ours. [1]","blocks":[{"type":"paragraph","text":"Pastor Ade taught that forgiving is not forgetting; it is releasing the debt. [1]","source_refs":[1]}],"follow_ups":["What did we teach about reconciliation?"],"sources":[{"number":1,"title":"Seventy times seven","excerpt":"We forgive because we were forgiven.","teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","at_ms":754000,"at":"12:34","speaker":"Pastor Ade","recorded_on":"2026-06-14","standing":"current","quote_verified":true}],"standing":[],"next_steps":[],"shareable":true,"created_at":"2026-11-01T14:00:09Z"}]}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/ConversationWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Read a conversation.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["ask:read"]}],"summary":"Read a conversation","tags":["Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["ask:read"]}},"/v1/conversations/{conversation}/messages":{"post":{"description":"Adds a question to an existing conversation. Without `stream`, the response is the same turn object as when you start a conversation, with a `pending` answer to poll for. With `\"stream\": true` the response is a server-sent event stream: a `turn.created` event first, then answer events until the answer is final.\n\nOnly one answer can be written at a time. Asking while one is pending answers 409 \"An answer is already being written.\"; wait for it or stop it.\n\n**Auth.** A church API key. Needs the `ask:create` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Plan.** Counts against the plan's Ask allowance like any question.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineCreateMessage","parameters":[{"description":"The conversation id, such as conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"conversation","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"input":"And what about forgiving someone who has not apologised?","stream":false}}},"schema":{"$ref":"#/components/schemas/MachineCreateMessageInputBody"}}},"required":true},"responses":{"200":{"content":{"text/event-stream":{"example":"event: answer\ndata: {\"text\":\"…\"}\n\n","schema":{"type":"string"}}},"description":"Success. Ask a follow-up question.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"402":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This church has used its Ask allowance for this month.","error":{"code":"quota_exceeded","status":402,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The Ask allowance or the AI budget is used up."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"An answer is already being written.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"An answer is already being written for this conversation.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["ask:create"]}],"summary":"Ask a follow-up question","tags":["Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/messages\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: faq-forgiveness-2\" \\\n  -d '{\n  \"input\": \"And what about forgiving someone who has not apologised?\",\n  \"stream\": false\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/messages`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"faq-forgiveness-2\",\n  },\n  body: JSON.stringify({\n    \"input\": \"And what about forgiving someone who has not apologised?\",\n    \"stream\": false\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/messages\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n        \"Idempotency-Key\": \"faq-forgiveness-2\",\n    },\n    json={\n        \"input\": \"And what about forgiving someone who has not apologised?\",\n        \"stream\": False,\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"input\": \"And what about forgiving someone who has not apologised?\",\n  \"stream\": false\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/messages\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"faq-forgiveness-2\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Counts against the plan's Ask allowance like any question.","x-rate-limited":true,"x-required-scopes":["ask:create"]}},"/v1/conversations/{conversation}/stop":{"post":{"description":"Stops the answer that is being written. The answer ends with `kind` `stopped`. Calling it when nothing is pending is harmless.\n\n**Auth.** A church API key. Needs the `ask:create` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineStopConversation","parameters":[{"description":"The conversation id, such as conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"conversation","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"answer stopped","data":null}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Stop the current answer.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["ask:create"]}],"summary":"Stop the current answer","tags":["Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/stop\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/stop`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/stop\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/stop\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["ask:create"]}},"/v1/device/commands":{"get":{"description":"Holds the request open for up to `wait` seconds (capped by the server, 25 by default) and returns commands queued for this booth after `since`. Kinds: `sync_now` (pull the library), `update_available` and `revoke` (acknowledging it revokes the key). Store `next_since` and send it on the next poll. Acknowledge each command.\n\n**Auth.** A booth device key. Needs the `device:read` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceCommands","parameters":[{"description":"Return commands after this sequence number.","example":"0","explode":false,"in":"query","name":"since","schema":{"description":"Return commands after this sequence number.","format":"int64","minimum":0,"type":"integer"}},{"description":"Seconds to hold the request open when nothing is queued. Capped by the server.","example":"25","explode":false,"in":"query","name":"wait","schema":{"description":"Seconds to hold the request open when nothing is queued. Capped by the server.","format":"int64","maximum":55,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device_commands","data":{"object":"device_commands","commands":[{"id":"cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"device_command","seq":7,"kind":"sync_now","payload":{},"created_at":"2026-11-01T08:00:00Z"}],"next_since":7}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDeviceCommandsWire"}}},"description":"Success. Long-poll for commands.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:read"]}],"summary":"Long-poll for commands","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/device/commands?since=0&wait=25\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/commands?since=0&wait=25`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/commands?since=0&wait=25\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/commands?since=0&wait=25\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:read"]}},"/v1/device/commands/{command}/ack":{"post":{"description":"Marks a command as handled. Acknowledging a `revoke` command revokes the device key, so the booth's next call answers 401.\n\n**Auth.** A booth device key. Needs the `device:write` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceAckCommand","parameters":[{"description":"The command id from GET /v1/device/commands.","example":"cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"command","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device_command","data":{"id":"cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"device_command","seq":7,"kind":"sync_now","payload":{},"created_at":"2026-11-01T08:00:00Z"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDeviceCommandWire"}}},"description":"Success. Acknowledge a command.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:write"]}],"summary":"Acknowledge a command","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/device/commands/cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/ack\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/commands/cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/ack`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/commands/cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/ack\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/commands/cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/ack\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:write"]}},"/v1/device/events":{"post":{"description":"Sends events recorded during a service, such as songs shown. Events are deduplicated by their `id`, so resending a batch after a dropped connection is safe. Send up to 500 at a time.\n\n**Auth.** A booth device key. Needs the `device:write` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceRecordEvents","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"events":[{"id":"evt-1730451600-1","kind":"song.shown","at_ms":1730451600000,"payload":"{\"song\":\"amazing-grace\"}"}]}}},"schema":{"$ref":"#/components/schemas/DeviceEventsInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device_events","data":{"object":"device_events","stored":1}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDeviceEventsWire"}}},"description":"Success. Push service events.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:write"]}],"summary":"Push service events","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/device/events\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"X-Folio-Device-Contract: 1\" \\\n  -d '{\n  \"events\": [\n    {\n      \"id\": \"evt-1730451600-1\",\n      \"kind\": \"song.shown\",\n      \"at_ms\": 1730451600000,\n      \"payload\": \"{\\\"song\\\":\\\"amazing-grace\\\"}\"\n    }\n  ]\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/events`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n  body: JSON.stringify({\n    \"events\": [\n      {\n        \"id\": \"evt-1730451600-1\",\n        \"kind\": \"song.shown\",\n        \"at_ms\": 1730451600000,\n        \"payload\": \"{\\\"song\\\":\\\"amazing-grace\\\"}\"\n      }\n    ]\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/events\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    json={\n        \"events\": [\n            {\n                \"id\": \"evt-1730451600-1\",\n                \"kind\": \"song.shown\",\n                \"at_ms\": 1730451600000,\n                \"payload\": \"{\\\"song\\\":\\\"amazing-grace\\\"}\",\n            },\n        ],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"events\": [\n    {\n      \"id\": \"evt-1730451600-1\",\n      \"kind\": \"song.shown\",\n      \"at_ms\": 1730451600000,\n      \"payload\": \"{\\\"song\\\":\\\"amazing-grace\\\"}\"\n    }\n  ]\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/events\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:write"]}},"/v1/device/library/changes":{"get":{"description":"Returns objects changed since a library `version`. Pull with `since=<next_since>` until `more` is false, and store the last `next_since`. Deletes appear as tombstones with `deleted: true`. Narrow with `kinds`.\n\n**Auth.** A booth device key. Needs the `device:read` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceLibraryChanges","parameters":[{"description":"Return what changed after this value. Start at 0 and pass the last next_since you received.","example":"400","explode":false,"in":"query","name":"since","schema":{"format":"int64","minimum":0,"type":"integer"}},{"description":"Only these kinds of object: song, theme, service_plan or service_record. Repeat the parameter for several.","explode":false,"in":"query","name":"kinds","schema":{"items":{"type":"string"},"maxItems":4,"type":["array","null"]}},{"description":"How many items to return, from 1 to 100.","example":"100","explode":false,"in":"query","name":"limit","schema":{"format":"int64","maximum":200,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"library_changes","data":{"object":"library_changes","objects":[{"object":"library_object","kind":"song","id":"song-amazing-grace","version":412,"revision":3,"hash":"9b74c9897bac770ffc029102a200c5de","title":"Amazing Grace","deleted":false,"updated_at":"2026-11-01T08:00:00Z","updated_by":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","updated_by_kind":"user","body":{"title":"Amazing Grace","verses":["Amazing grace, how sweet the sound"]}}],"next_since":412,"more":false}}}},"schema":{"$ref":"#/components/schemas/TypedBodyLibraryChangesWire"}}},"description":"Success. Pull library changes.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:read"]}],"summary":"Pull library changes","tags":["Booth library"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/device/library/changes?limit=100&since=400\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/library/changes?limit=100&since=400`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/library/changes?limit=100&since=400\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/library/changes?limit=100&since=400\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:read"]}},"/v1/device/library/objects":{"post":{"description":"Writes up to 100 objects. Each carries the `base_revision` you last saw. If someone changed the object meanwhile, its result is a conflict that includes the current object; merge and retry that object. Results come back per object so one conflict does not fail the batch.\n\n**Auth.** A booth device key. Needs the `device:write` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceLibraryPush","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"objects":[{"kind":"song","id":"song-amazing-grace","base_revision":3,"checksum":"9b74c9897bac770ffc029102a200c5de","body":{"title":"Amazing Grace","verses":["Amazing grace, how sweet the sound"]}}]}}},"schema":{"$ref":"#/components/schemas/LibraryPushInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"library_push","data":{"object":"library_push","results":[{"kind":"song","id":"song-amazing-grace","outcome":"applied","object":{"object":"library_object","kind":"song","id":"song-amazing-grace","version":412,"revision":3,"hash":"9b74c9897bac770ffc029102a200c5de","title":"Amazing Grace","deleted":false,"updated_at":"2026-11-01T08:00:00Z","updated_by":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","updated_by_kind":"user","body":{"title":"Amazing Grace","verses":["Amazing grace, how sweet the sound"]}}}]}}}},"schema":{"$ref":"#/components/schemas/TypedBodyLibraryPushWire"}}},"description":"Success. Push a batch of library objects.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:write"]}],"summary":"Push a batch of library objects","tags":["Booth library"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/device/library/objects\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: push-2026-11-01-1\" \\\n  -H \"X-Folio-Device-Contract: 1\" \\\n  -d '{\n  \"objects\": [\n    {\n      \"kind\": \"song\",\n      \"id\": \"song-amazing-grace\",\n      \"base_revision\": 3,\n      \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n      \"body\": {\n        \"title\": \"Amazing Grace\",\n        \"verses\": [\n          \"Amazing grace, how sweet the sound\"\n        ]\n      }\n    }\n  ]\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/library/objects`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"push-2026-11-01-1\",\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n  body: JSON.stringify({\n    \"objects\": [\n      {\n        \"kind\": \"song\",\n        \"id\": \"song-amazing-grace\",\n        \"base_revision\": 3,\n        \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n        \"body\": {\n          \"title\": \"Amazing Grace\",\n          \"verses\": [\n            \"Amazing grace, how sweet the sound\"\n          ]\n        }\n      }\n    ]\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/library/objects\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"Idempotency-Key\": \"push-2026-11-01-1\",\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    json={\n        \"objects\": [\n            {\n                \"kind\": \"song\",\n                \"id\": \"song-amazing-grace\",\n                \"base_revision\": 3,\n                \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n                \"body\": {\n                    \"title\": \"Amazing Grace\",\n                    \"verses\": [\n                        \"Amazing grace, how sweet the sound\",\n                    ],\n                },\n            },\n        ],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"objects\": [\n    {\n      \"kind\": \"song\",\n      \"id\": \"song-amazing-grace\",\n      \"base_revision\": 3,\n      \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n      \"body\": {\n        \"title\": \"Amazing Grace\",\n        \"verses\": [\n          \"Amazing grace, how sweet the sound\"\n        ]\n      }\n    }\n  ]\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/library/objects\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"push-2026-11-01-1\")\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:write"]}},"/v1/device/library/objects/{kind}/{id}":{"delete":{"description":"Marks the object deleted by writing a tombstone, so other booths learn of the delete on their next pull. Pass `base_revision` to avoid deleting a change you have not seen.\n\n**Auth.** A booth device key. Needs the `device:write` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceLibraryDelete","parameters":[{"description":"The object kind: song, theme, service_plan or service_record.","example":"song","in":"path","name":"kind","required":true,"schema":{"enum":["song","theme","service_plan","service_record"],"type":"string"}},{"description":"The object id.","example":"song-amazing-grace","in":"path","name":"id","required":true,"schema":{"maxLength":64,"minLength":1,"type":"string"}},{"description":"The revision you last read. A stale value is refused so you do not delete a change you have not seen.","example":"4","explode":false,"in":"query","name":"base_revision","schema":{"format":"int32","minimum":0,"type":"integer"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"library_object","data":{"object":"library_object","kind":"song","id":"song-amazing-grace","deleted":true}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Delete one library object.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:write"]}],"summary":"Delete one library object","tags":["Booth library"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X DELETE \"$FOLIO_API_URL/v1/device/library/objects/song/song-amazing-grace?base_revision=4\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/library/objects/song/song-amazing-grace?base_revision=4`, {\n  method: \"DELETE\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/library/objects/song/song-amazing-grace?base_revision=4\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"DELETE\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/library/objects/song/song-amazing-grace?base_revision=4\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:write"]},"get":{"description":"Returns one object with its body, current revision and hash.\n\n**Auth.** A booth device key. Needs the `device:read` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceLibraryGet","parameters":[{"description":"The object kind: song, theme, service_plan or service_record.","example":"song","in":"path","name":"kind","required":true,"schema":{"enum":["song","theme","service_plan","service_record"],"type":"string"}},{"description":"The object id.","example":"song-amazing-grace","in":"path","name":"id","required":true,"schema":{"maxLength":64,"minLength":1,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"library_object","data":{"object":"library_object","kind":"song","id":"song-amazing-grace","version":412,"revision":3,"hash":"9b74c9897bac770ffc029102a200c5de","title":"Amazing Grace","deleted":false,"updated_at":"2026-11-01T08:00:00Z","updated_by":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","updated_by_kind":"user","body":{"title":"Amazing Grace","verses":["Amazing grace, how sweet the sound"]}}}}},"schema":{"$ref":"#/components/schemas/TypedBodyLibraryObjectWire"}}},"description":"Success. Read one library object.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:read"]}],"summary":"Read one library object","tags":["Booth library"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/device/library/objects/song/song-amazing-grace\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/library/objects/song/song-amazing-grace`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/library/objects/song/song-amazing-grace\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/library/objects/song/song-amazing-grace\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:read"]},"put":{"description":"Creates or replaces one object. `base_revision` is the revision you last read (0 to create). A stale revision answers a conflict with the current object so you can merge.\n\n**Auth.** A booth device key. Needs the `device:write` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceLibraryPut","parameters":[{"description":"The object kind: song, theme, service_plan or service_record.","example":"song","in":"path","name":"kind","required":true,"schema":{"enum":["song","theme","service_plan","service_record"],"type":"string"}},{"description":"The object id.","example":"song-amazing-grace","in":"path","name":"id","required":true,"schema":{"maxLength":64,"minLength":1,"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"base_revision":3,"checksum":"9b74c9897bac770ffc029102a200c5de","body":{"title":"Amazing Grace","verses":["Amazing grace, how sweet the sound"]}}}},"schema":{"$ref":"#/components/schemas/LibraryPutBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"library_object","data":{"object":"library_object","kind":"song","id":"song-amazing-grace","version":412,"revision":3,"hash":"9b74c9897bac770ffc029102a200c5de","title":"Amazing Grace","deleted":false,"updated_at":"2026-11-01T08:00:00Z","updated_by":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","updated_by_kind":"user","body":{"title":"Amazing Grace","verses":["Amazing grace, how sweet the sound"]}}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Write one library object.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:write"]}],"summary":"Write one library object","tags":["Booth library"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X PUT \"$FOLIO_API_URL/v1/device/library/objects/song/song-amazing-grace\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: put-song-amazing-grace-4\" \\\n  -H \"X-Folio-Device-Contract: 1\" \\\n  -d '{\n  \"base_revision\": 3,\n  \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n  \"body\": {\n    \"title\": \"Amazing Grace\",\n    \"verses\": [\n      \"Amazing grace, how sweet the sound\"\n    ]\n  }\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/library/objects/song/song-amazing-grace`, {\n  method: \"PUT\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"put-song-amazing-grace-4\",\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n  body: JSON.stringify({\n    \"base_revision\": 3,\n    \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n    \"body\": {\n      \"title\": \"Amazing Grace\",\n      \"verses\": [\n        \"Amazing grace, how sweet the sound\"\n      ]\n    }\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"PUT\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/library/objects/song/song-amazing-grace\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"Idempotency-Key\": \"put-song-amazing-grace-4\",\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    json={\n        \"base_revision\": 3,\n        \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n        \"body\": {\n            \"title\": \"Amazing Grace\",\n            \"verses\": [\n                \"Amazing grace, how sweet the sound\",\n            ],\n        },\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"base_revision\": 3,\n  \"checksum\": \"9b74c9897bac770ffc029102a200c5de\",\n  \"body\": {\n    \"title\": \"Amazing Grace\",\n    \"verses\": [\n      \"Amazing grace, how sweet the sound\"\n    ]\n  }\n}`)\n\trequest, err := http.NewRequest(\"PUT\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/library/objects/song/song-amazing-grace\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"put-song-amazing-grace-4\")\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:write"]}},"/v1/device/me":{"get":{"description":"Returns the booth the key belongs to, its church and its scopes. A revoked key answers 401 here; treat that as revoked and forget the key.\n\n**Auth.** A booth device key. Needs the `device:read` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceMe","responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device","data":{"object":"device","id":"dev_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","label":"Sanctuary booth","org":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","scopes":["device:read","device:write"]}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDeviceMeWire"}}},"description":"Success. Who this key is.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:read"]}],"summary":"Who this key is","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/device/me\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/me`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/me\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/me\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:read"]}},"/v1/device/packs":{"get":{"description":"Lists song packs and the King James Version text pack the booth can download for offline use. Scripture on the booth is King James Version only.\n\n**Auth.** A booth device key. Needs the `device:read` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"devicePacks","responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device_packs","data":{"object":"device_packs","songs":[{"id":"worship-2026","name":"Worship 2026","version":3}],"translations":[{"code":"KJV","name":"King James Version","version":1}]}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDevicePacksWire"}}},"description":"Success. List downloadable packs.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:read"]}],"summary":"List downloadable packs","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/device/packs\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/packs`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/packs\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/packs\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:read"]}},"/v1/device/plans/{plan}":{"get":{"description":"Returns the service plan with the given id, or the latest with `current`. The body is the plan document the booth runs the service from.\n\n**Auth.** A booth device key. Needs the `device:read` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"devicePlan","parameters":[{"description":"The service plan id, or current for the latest.","example":"current","in":"path","name":"plan","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device_plan","data":{"id":"plan_2026_11_01","title":"Sunday 1 November","items":[{"kind":"song","ref":"song-amazing-grace"}]}}}},"schema":{"$ref":"#/components/schemas/TypedBodyRawMessage"}}},"description":"Success. Read a service plan.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:read"]}],"summary":"Read a service plan","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/device/plans/current\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/plans/current`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/plans/current\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/plans/current\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:read"]}},"/v1/device/teachings":{"post":{"description":"The booth's version of creating a teaching: it returns a signed upload URL and a `key`. `PUT` the recording to `url`, then call `POST /v1/device/teachings/{teaching}/upload` with `key`. The same plan checks apply as for an API key, so the booth needs no second credential.\n\n**Auth.** A booth device key. Needs the `device:write` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Plan.** Needs the booth feature and transcription hours left in the plan (402 `quota_exceeded` otherwise).\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceCreateTeaching","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"title":"Sunday service","filename":"service.mp4","content_type":"video/mp4"}}},"schema":{"$ref":"#/components/schemas/DeviceTeachingInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"upload ready","data":{"object":"upload","teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/service.mp4","url":"https://files.example.org/originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/service.mp4?X-Signature=abc123","expires_at":"2026-11-01T10:15:00Z"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDeviceUploadWire"}}},"description":"Success. Create a teaching from a booth recording.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:write"]}],"summary":"Create a teaching from a booth recording","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/device/teachings\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: booth-service-2026-11-01\" \\\n  -H \"X-Folio-Device-Contract: 1\" \\\n  -d '{\n  \"title\": \"Sunday service\",\n  \"filename\": \"service.mp4\",\n  \"content_type\": \"video/mp4\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/teachings`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"booth-service-2026-11-01\",\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n  body: JSON.stringify({\n    \"title\": \"Sunday service\",\n    \"filename\": \"service.mp4\",\n    \"content_type\": \"video/mp4\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/teachings\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"Idempotency-Key\": \"booth-service-2026-11-01\",\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    json={\n        \"title\": \"Sunday service\",\n        \"filename\": \"service.mp4\",\n        \"content_type\": \"video/mp4\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"title\": \"Sunday service\",\n  \"filename\": \"service.mp4\",\n  \"content_type\": \"video/mp4\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/teachings\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"booth-service-2026-11-01\")\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the booth feature and transcription hours left in the plan (402 `quota_exceeded` otherwise).","x-rate-limited":true,"x-required-scopes":["device:write"]}},"/v1/device/teachings/{teaching}/upload":{"post":{"description":"Tells Folio the recording is in storage and starts processing.\n\n**Auth.** A booth device key. Needs the `device:write` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceCompleteUpload","parameters":[{"description":"The teaching id, such as tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"teaching","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"key":"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/service.mp4"}}},"schema":{"$ref":"#/components/schemas/DeviceCompleteUploadInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"upload received","data":{"object":"teaching","teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDeviceUploadDoneWire"}}},"description":"Success. Finish a booth upload.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This booth must update Folio Live.","error":{"code":"failed_precondition","status":426,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The booth's contract version is no longer supported. Call GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:write"]}],"summary":"Finish a booth upload","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/device/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"X-Folio-Device-Contract: 1\" \\\n  -d '{\n  \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/service.mp4\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n  body: JSON.stringify({\n    \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/service.mp4\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    json={\n        \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/service.mp4\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/service.mp4\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:write"]}},"/v1/device/update":{"get":{"description":"Returns the latest and the minimum supported version for a platform, and where to download. It works even when `X-Folio-Device-Contract` is too old, so a stale booth can learn where to update. `update_required` means the booth must update before other calls succeed.\n\n**Auth.** A booth device key. Needs the `device:read` scope. Send `X-Folio-Device-Contract`; an unsupported version gets 426.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"deviceUpdate","parameters":[{"description":"For example windows, macos or linux.","example":"windows","explode":false,"in":"query","name":"platform","schema":{"description":"For example windows, macos or linux.","maxLength":32,"type":"string"}},{"description":"The version the booth runs now, such as 1.4.2.","example":"1.4.2","explode":false,"in":"query","name":"current","schema":{"description":"The version the booth runs now, such as 1.4.2.","maxLength":32,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device_update","data":{"object":"device_update","platform":"windows","current":"1.4.2","latest":"1.5.0","min_supported":"1.4.0","update_available":true,"update_required":false,"url":"https://downloads.example.org/folio-live/windows/1.5.0","notes":"Faster library sync.","contract":{"current":1,"minimum":1}}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDeviceUpdateWire"}}},"description":"Success. Check for a Folio Live update.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"426":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"This booth must update Folio Live. See GET /v1/device/update."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"deviceKey":["device:read"]}],"summary":"Check for a Folio Live update","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/device/update?current=1.4.2&platform=windows\" \\\n  -H \"Authorization: Bearer $FOLIO_DEVICE_KEY\" \\\n  -H \"X-Folio-Device-Contract: 1\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/device/update?current=1.4.2&platform=windows`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_DEVICE_KEY}`,\n    \"X-Folio-Device-Contract\": \"1\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/device/update?current=1.4.2&platform=windows\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_DEVICE_KEY\"],\n        \"X-Folio-Device-Contract\": \"1\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/device/update?current=1.4.2&platform=windows\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_DEVICE_KEY\"))\n\trequest.Header.Set(\"X-Folio-Device-Contract\", \"1\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["device:read"]}},"/v1/devices/pair":{"post":{"description":"A booth sends the six-digit code a team member created in the console. The code is single use and valid for 10 minutes. The response holds the device `key` (`folio_booth_…`) exactly once; store it securely on the booth.\n\nThis route is public because the booth has no key yet. It is rate limited per client address and per code prefix; past the limit it answers 429. Unknown, expired and used codes all answer the same 422, so a guess reveals nothing. Codes are stored hashed.\n\n**Auth.** None. This route is public.\n\n**Plan.** The church needs the booth feature.","operationId":"claimDevicePairing","requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"code":"482913"}}},"schema":{"$ref":"#/components/schemas/ClaimDevicePairingInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"device paired","data":{"object":"device_pairing","paired":true,"id":"dev_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","device":"Sanctuary booth","key":"folio_booth_a1b2c3d4e5f60718293a4b5c6d7e8f90"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyDevicePairedWire"}}},"description":"Success. Trade a pairing code for a device key."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That code is not valid. Ask for a new one.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The code is unknown, expired or already used."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Trade a pairing code for a device key","tags":["Booth devices"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/devices/pair\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"code\": \"482913\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/devices/pair`, {\n  method: \"POST\",\n  headers: {\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"code\": \"482913\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/devices/pair\",\n    headers={\n    },\n    json={\n        \"code\": \"482913\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"code\": \"482913\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/devices/pair\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"The church needs the booth feature."}},"/v1/links":{"get":{"description":"Lists the links between this church and others in a network, including requests waiting for an answer.\n\n**Auth.** A church API key. Needs the `networks:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListLinks","parameters":[{"description":"Items per page.","explode":false,"in":"query","name":"limit","schema":{"default":50,"description":"Items per page.","format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from meta.next_cursor of the previous page.","explode":false,"in":"query","name":"cursor","schema":{"description":"Opaque cursor from meta.next_cursor of the previous page.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"links","data":[{"id":"lnk_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"link","status":"accepted","incoming":false,"requester_org":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","target_org":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099","other_church":"Hope Fellowship","other_slug":"hope-fellowship","requested_label":"Sister church"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyLinkWire"}}},"description":"Success. List church links.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["networks:read"]}],"summary":"List church links","tags":["Networks"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/links\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/links`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/links\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/links\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["networks:read"]}},"/v1/notes":{"get":{"description":"Lists the church's published notes. Keys never see drafts, notes in review or retired notes. Because unpublished notes are filtered out after the page is cut, a page can hold fewer items than `limit` while `has_next` is still true; keep following `next_cursor`.\n\n**Auth.** A church API key. Needs the `notes:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListNotes","parameters":[{"description":"Items per page.","example":"20","explode":false,"in":"query","name":"limit","schema":{"default":50,"description":"Items per page.","format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from meta.next_cursor of the previous page.","explode":false,"in":"query","name":"cursor","schema":{"description":"Opaque cursor from meta.next_cursor of the previous page.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"notes","data":[{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"teaching","name":"Sunday, 1 November: Nothing can separate us"},"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."}],"approval_kind":"human","approved_at":"2026-11-01T12:30:00Z","published_at":"2026-11-01T12:31:00Z","created_at":"2026-11-01T10:20:00Z","updated_at":"2026-11-01T12:31:00Z","share_slug":"nothing-can-separate-us","share_path":"/grace-chapel/notes/nothing-can-separate-us"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MachineNoteWire"},"type":"array"},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/ListMeta"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. List published notes.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["notes:read"]}],"summary":"List published notes","tags":["Notes"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/notes?limit=20\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/notes?limit=20`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/notes?limit=20\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/notes?limit=20\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["notes:read"]}},"/v1/notes/{note}":{"get":{"description":"Returns one published note. A note that exists but is not published answers 404, the same as an unknown id. Verses quoted in a note are checked against the King James Version before the note can be approved.\n\n**Auth.** A church API key. Needs the `notes:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetNote","parameters":[{"description":"The note id, prefixed note_.","example":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"note","required":true,"schema":{"description":"The note id, prefixed note_.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"note","data":{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"teaching","name":"Sunday, 1 November: Nothing can separate us"},"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."}],"approval_kind":"automatic","approved_at":"2026-11-01T12:30:00Z","published_at":"2026-11-01T12:31:00Z","created_at":"2026-11-01T10:20:00Z","updated_at":"2026-11-01T12:31:00Z","share_slug":"nothing-can-separate-us","share_path":"/grace-chapel/notes/nothing-can-separate-us"}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/MachineNoteWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Read a published note.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["notes:read"]}],"summary":"Read a published note","tags":["Notes"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/notes/note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/notes/note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/notes/note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/notes/note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["notes:read"]}},"/v1/outputs":{"get":{"description":"Lists published outputs: devotionals, blog posts, newsletters and study guides written from a note. Pass `teaching` to see the outputs of one teaching. Drafts and outputs in review are never returned to a key. If the note an output was written from changes, the output is taken back to review and disappears from this list until it is published again; the `output.unpublished` webhook tells you.\n\n**Auth.** A church API key. Needs the `outputs:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListOutputs","parameters":[{"description":"Only outputs written from this teaching.","example":"{{tch}}","explode":false,"in":"query","name":"teaching","schema":{"description":"Only outputs written from this teaching.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"outputs","data":[{"id":"out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"output","teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"devotional","status":"published","language":"en","title":"Held by a love that does not let go","body_md":"Paul's question in Romans 8 is not rhetorical…","meta":{},"verses":[{"ref":"Romans 8:38-39","status":"verified"}],"word_count":312,"updated_at":"2026-11-02T08:00:00Z"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MachineOutputWire"},"type":"array"},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/ListMeta"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. List published outputs.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["outputs:read"]}],"summary":"List published outputs","tags":["Outputs"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/outputs?teaching=%7B%7Btch%7D%7D\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/outputs?teaching=%7B%7Btch%7D%7D`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/outputs?teaching=%7B%7Btch%7D%7D\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/outputs?teaching=%7B%7Btch%7D%7D\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["outputs:read"]}},"/v1/outputs/{output}":{"get":{"description":"Returns one published output with its full Markdown body. Anything that is not published answers 404.\n\n**Auth.** A church API key. Needs the `outputs:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetOutput","parameters":[{"description":"The output id, prefixed out_.","example":"out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"output","required":true,"schema":{"description":"The output id, prefixed out_.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"output","data":{"id":"out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"output","teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"devotional","status":"published","language":"en","title":"Held by a love that does not let go","body_md":"Paul's question in Romans 8 is not rhetorical…","meta":{},"verses":[{"ref":"Romans 8:38-39","status":"verified"}],"word_count":312,"updated_at":"2026-11-02T08:00:00Z"}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/MachineOutputWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Read a published output.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["outputs:read"]}],"summary":"Read a published output","tags":["Outputs"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/outputs/out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/outputs/out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/outputs/out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/outputs/out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["outputs:read"]}},"/v1/partner":{"get":{"description":"Returns whether the key belongs to a partner church, the programme grants it has, and how many customer churches it runs. A good first call to check a partner key works.\n\n**Auth.** A partner key. Needs the `partners:read` scope, or a wildcard that includes it (`machine:read`, `*` on a partner key).\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machinePartnerOverview","responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"partner","data":{"is_partner":true,"grants":["partners"],"churches":3}}}},"schema":{"$ref":"#/components/schemas/TypedBodyPartnerOverviewWire"}}},"description":"Success. Read the partner overview.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"partnerKey":["partners:read"]}],"summary":"Read the partner overview","tags":["Partners"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/partner\" \\\n  -H \"Authorization: Bearer $FOLIO_PARTNER_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/partner`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_PARTNER_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/partner\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_PARTNER_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/partner\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_PARTNER_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["partners:read"]}},"/v1/partner/churches":{"get":{"description":"Lists the churches this partner created or runs, including sandbox churches with their `expires_at`. A key limited to some churches (`church_ids`) sees only those.\n\n**Auth.** A partner key. Needs the `partners:read` scope, or a wildcard that includes it (`machine:read`, `*` on a partner key).\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machinePartnerChurches","parameters":[{"description":"Items per page.","explode":false,"in":"query","name":"limit","schema":{"default":50,"description":"Items per page.","format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from meta.next_cursor of the previous page.","explode":false,"in":"query","name":"cursor","schema":{"description":"Opaque cursor from meta.next_cursor of the previous page.","type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"partner_churches","data":[{"id":"sac_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"church","church_id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Chapel","slug":"grace-chapel","admin_email":"pastor@grace.example","sandbox":false,"expires_at":null}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyPartnerChurchWire"}}},"description":"Success. List customer churches.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"partnerKey":["partners:read"]}],"summary":"List customer churches","tags":["Partners"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/partner/churches\" \\\n  -H \"Authorization: Bearer $FOLIO_PARTNER_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/partner/churches`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_PARTNER_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/partner/churches\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_PARTNER_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/partner/churches\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_PARTNER_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["partners:read"]},"post":{"description":"Creates a customer church, or with `sandbox: true` a free sandbox church for development. The admin is invited by email at `admin_email` (sandbox churches send no email).\n\nA sandbox church is not metered, takes only `folio_test_` keys, holds at most 20 teachings, has a small AI budget, and is deleted after 30 days. Calls in a sandbox use the real transcription and AI providers under those caps, so keep recordings short. Live captions, the booth, audience email, publishing, networks, care, SSO, the widget, exports and outbound webhooks are switched off.\n\n**Auth.** A partner key. Needs the `partners:write` scope, or a wildcard that includes it (`*` on a partner key).\n\n**Plan.** Needs the Partner plan with the partners feature. A live church counts against the partner's churches meter. A partner can hold at most 25 sandbox churches.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machinePartnerCreateChurch","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"name":"Grace Chapel","slug":"grace-chapel","admin_email":"pastor@grace.example","sandbox":false}}},"schema":{"$ref":"#/components/schemas/PartnerCreateChurchInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"partner_church","data":{"id":"sac_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"church","church_id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Chapel","slug":"grace-chapel","admin_email":"pastor@grace.example","sandbox":false,"expires_at":null}}}},"schema":{"$ref":"#/components/schemas/TypedBodyPartnerChurchWire"}}},"description":"Success. Create a customer church.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"402":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This partner has reached its church allowance.","error":{"code":"quota_exceeded","status":402,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The partner reached its church allowance or the sandbox limit."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That slug is taken.","error":{"code":"already_exists","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The slug is already used.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"partnerKey":["partners:write"]}],"summary":"Create a customer church","tags":["Partners"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/partner/churches\" \\\n  -H \"Authorization: Bearer $FOLIO_PARTNER_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: customer-grace-chapel\" \\\n  -d '{\n  \"name\": \"Grace Chapel\",\n  \"slug\": \"grace-chapel\",\n  \"admin_email\": \"pastor@grace.example\",\n  \"sandbox\": false\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/partner/churches`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_PARTNER_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"customer-grace-chapel\",\n  },\n  body: JSON.stringify({\n    \"name\": \"Grace Chapel\",\n    \"slug\": \"grace-chapel\",\n    \"admin_email\": \"pastor@grace.example\",\n    \"sandbox\": false\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/partner/churches\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_PARTNER_KEY\"],\n        \"Idempotency-Key\": \"customer-grace-chapel\",\n    },\n    json={\n        \"name\": \"Grace Chapel\",\n        \"slug\": \"grace-chapel\",\n        \"admin_email\": \"pastor@grace.example\",\n        \"sandbox\": False,\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"name\": \"Grace Chapel\",\n  \"slug\": \"grace-chapel\",\n  \"admin_email\": \"pastor@grace.example\",\n  \"sandbox\": false\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/partner/churches\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_PARTNER_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"customer-grace-chapel\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the Partner plan with the partners feature. A live church counts against the partner's churches meter. A partner can hold at most 25 sandbox churches.","x-rate-limited":true,"x-required-scopes":["partners:write"]}},"/v1/partner/churches/{church}/keys":{"get":{"description":"Lists the keys issued for a customer church: prefix, last four characters, scopes, mode and last use. The secrets are never shown again.\n\n**Auth.** A partner key. Needs the `partners:read` scope, or a wildcard that includes it (`machine:read`, `*` on a partner key).\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machinePartnerListKeys","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"api_keys","data":[{"id":"key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"CRM sync","prefix":"a1b2c3d4","last4":"9f2e","scopes":["teachings:read","notes:read"],"mode":"live","partner":false,"church_ids":[],"ip_allowlist":[],"rate_limit_per_minute":null,"created_at":"2026-10-20T09:00:00Z","expires_at":null,"last_used_at":"2026-11-01T12:00:00Z","last_used_ip":"203.0.113.7","request_count":128,"rotated_from":null}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyApiKeyWire"}}},"description":"Success. List keys for a church.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"partnerKey":["partners:read"]}],"summary":"List keys for a church","tags":["Partners"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/partner/churches/grace-chapel/keys\" \\\n  -H \"Authorization: Bearer $FOLIO_PARTNER_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/partner/churches/grace-chapel/keys`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_PARTNER_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/partner/churches/grace-chapel/keys\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_PARTNER_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/partner/churches/grace-chapel/keys\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_PARTNER_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["partners:read"]},"post":{"description":"Issues a church key for a customer church, to hand to that church's own system. It can carry only scopes the partner's programme grants. The full `key` is in the response once; Folio stores only a hash. A sandbox church gets a `folio_test_` key and a live church a `folio_live_` key.\n\nPrefer one partner key with `X-Folio-Church` when your own server calls on the church's behalf; issue a church key when the church's system calls directly.\n\n**Auth.** A partner key. Needs the `partners:write` scope, or a wildcard that includes it (`*` on a partner key).\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machinePartnerIssueKey","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"name":"CRM sync","scopes":["teachings:read","notes:read"]}}},"schema":{"$ref":"#/components/schemas/PartnerIssueKeyInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"api_key","data":{"id":"key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"api_key","key":"folio_live_a1b2c3d4e5f60718293a4b5c6d7e8f90","name":"CRM sync","scopes":["teachings:read","notes:read"],"mode":"live"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyPartnerKeyIssuedWire"}}},"description":"Success. Issue a scoped key for a church.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"partnerKey":["partners:write"]}],"summary":"Issue a scoped key for a church","tags":["Partners"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/partner/churches/grace-chapel/keys\" \\\n  -H \"Authorization: Bearer $FOLIO_PARTNER_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: grace-crm-key\" \\\n  -d '{\n  \"name\": \"CRM sync\",\n  \"scopes\": [\n    \"teachings:read\",\n    \"notes:read\"\n  ]\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/partner/churches/grace-chapel/keys`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_PARTNER_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"grace-crm-key\",\n  },\n  body: JSON.stringify({\n    \"name\": \"CRM sync\",\n    \"scopes\": [\n      \"teachings:read\",\n      \"notes:read\"\n    ]\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/partner/churches/grace-chapel/keys\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_PARTNER_KEY\"],\n        \"Idempotency-Key\": \"grace-crm-key\",\n    },\n    json={\n        \"name\": \"CRM sync\",\n        \"scopes\": [\n            \"teachings:read\",\n            \"notes:read\",\n        ],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"name\": \"CRM sync\",\n  \"scopes\": [\n    \"teachings:read\",\n    \"notes:read\"\n  ]\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/partner/churches/grace-chapel/keys\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_PARTNER_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"grace-crm-key\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["partners:write"]}},"/v1/partner/churches/{church}/keys/{key}":{"delete":{"description":"Revokes a key at once. The next call with it answers 401. Revoking is safe to repeat.\n\n**Auth.** A partner key. Needs the `partners:write` scope, or a wildcard that includes it (`*` on a partner key).\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machinePartnerRevokeKey","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The API key id, such as key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"key","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"api key revoked"}}},"schema":{"$ref":"#/components/schemas/AckBody"}}},"description":"Success. Revoke a church key.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"partnerKey":["partners:write"]}],"summary":"Revoke a church key","tags":["Partners"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X DELETE \"$FOLIO_API_URL/v1/partner/churches/grace-chapel/keys/key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\" \\\n  -H \"Authorization: Bearer $FOLIO_PARTNER_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/partner/churches/grace-chapel/keys/key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012`, {\n  method: \"DELETE\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_PARTNER_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/partner/churches/grace-chapel/keys/key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_PARTNER_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"DELETE\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/partner/churches/grace-chapel/keys/key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_PARTNER_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["partners:write"]}},"/v1/public/churches":{"get":{"description":"Lists the slugs of churches with published content, for site builders and sitemaps. Read a church's content with the other `/v1/public/{church}` routes.\n\n**Auth.** None. This route is public.","operationId":"publicChurches","responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"churches","data":[{"object":"church","slug":"grace-chapel"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. List churches that publish."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"List churches that publish","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/churches\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/churches`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/churches\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/churches\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/legal":{"get":{"description":"The current version, effective date and link of the Terms, the Privacy Policy and the Data Processing Addendum. Show the links and send the versions you displayed when a person accepts them. Send `If-None-Match` with the last `ETag` to get a cheap 304.\n\n**Auth.** None. This route is public.","operationId":"publicLegal","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"legal","data":{"object":"legal","documents":[{"document":"terms","version":"2026-10-25","effective_iso":"2026-10-25","effective_label":"25 October 2026","url":"https://folio.candensa.com/terms"}]}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read the current legal document versions.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read the current legal document versions","tags":["Plans and status"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/legal\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/legal`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/legal\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/legal\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/plans":{"get":{"description":"The plan catalogue: plans, their prices by interval and currency, the allowances each carries, per-unit prices for usage beyond the allowance, and add-ons. Show prices from here instead of copying them, because plans change. Send `If-None-Match` with the last `ETag` to get a cheap 304.\n\n**Auth.** None. This route is public.","operationId":"publicPlans","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"plans","data":{"trial_days":14,"plans":[{"key":"starter","name":"Starter","prices":[{"interval":"month","currency":"USD","amount":2900}],"entitlements":[{"feature":"hours","quota":480}],"meter_prices":[{"meter":"hours","amount":250}]}],"addons":[]}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read the plan catalogue.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read the plan catalogue","tags":["Plans and status"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/plans\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/plans`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/plans\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/plans\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/webhook-events":{"get":{"description":"The same catalogue as `GET /v1/webhook-event-types`, readable without a key so documentation and tooling can show the current events. It lists no church data.\n\n**Auth.** None. This route is public.","operationId":"publicWebhookEvents","responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_event_catalogue","data":{"groups":[{"key":"note","label":"Notes","events":[{"object":"webhook_event_type","type":"note.published","group":"note","group_label":"Notes","description":"A note was published to its share page.","source":"notes","fields":[{"name":"teaching_id","type":"string","required":true,"description":"The teaching this note belongs to."}],"example":{"type":"note.published"}}]}],"total":1,"all":"*"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyEventCatalogueWire"}}},"description":"Success. Read the webhook event catalogue without a key."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read the webhook event catalogue without a key","tags":["Plans and status"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/webhook-events\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/webhook-events`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/webhook-events\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/webhook-events\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/widget":{"get":{"description":"Resolves a site key (created in the console under Widget) for the calling origin. The browser sends `Origin`; the origin must be in the widget's allowlist or the call answers 403 `origin_not_allowed`. The site key is public and safe in page source.\n\n**Auth.** None. This route is public.\n\n**Plan.** The church needs the widget feature, and it must be on in the church's settings.","operationId":"widgetConfig","parameters":[{"description":"The widget's public site key, created in the console under Widget.","example":"wk_live_8f3a1c9d2b7e","explode":false,"in":"query","name":"key","schema":{"type":"string"}},{"description":"Sent by the browser: the page making the call. It must be in the widget's allowlist.","in":"header","name":"Origin","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"widget","data":{"object":"widget","church":"grace-chapel","name":"Grace Chapel","mode":"ask","settings":{"greeting":"Ask about our teaching"}}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Resolve a widget site key."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This site is not allowed to use this widget.","error":{"code":"origin_not_allowed","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The calling origin is not in the widget's allowlist."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Resolve a widget site key","tags":["Widget"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/widget?key=wk_live_8f3a1c9d2b7e\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/widget?key=wk_live_8f3a1c9d2b7e`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/widget?key=wk_live_8f3a1c9d2b7e\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/widget?key=wk_live_8f3a1c9d2b7e\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"The church needs the widget feature, and it must be on in the church's settings."}},"/v1/public/widget/handoff":{"post":{"description":"A visitor asks a pastor, or a crisis contact, to follow up. The church sees it in its care queue. Collect only what the visitor offers; `email` or `phone` lets the church reply.\n\n**Auth.** None. This route is public.","operationId":"widgetHandoff","parameters":[{"description":"The widget's public site key, created in the console under Widget.","example":"wk_live_8f3a1c9d2b7e","explode":false,"in":"query","name":"key","schema":{"type":"string"}},{"description":"Sent by the browser: the page making the call. It must be in the widget's allowlist.","in":"header","name":"Origin","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"kind":"pastor","name":"Ada","email":"ada@example.org","phone":"","question":"Could a pastor call me about forgiveness?"}}},"schema":{"$ref":"#/components/schemas/WidgetHandoffInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"handoff","data":{"id":"hof_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","status":"open"}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Hand a question to the church."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Hand a question to the church","tags":["Widget"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/public/widget/handoff?key=wk_live_8f3a1c9d2b7e\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"kind\": \"pastor\",\n  \"name\": \"Ada\",\n  \"email\": \"ada@example.org\",\n  \"phone\": \"\",\n  \"question\": \"Could a pastor call me about forgiveness?\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/widget/handoff?key=wk_live_8f3a1c9d2b7e`, {\n  method: \"POST\",\n  headers: {\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"kind\": \"pastor\",\n    \"name\": \"Ada\",\n    \"email\": \"ada@example.org\",\n    \"phone\": \"\",\n    \"question\": \"Could a pastor call me about forgiveness?\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/widget/handoff?key=wk_live_8f3a1c9d2b7e\",\n    headers={\n    },\n    json={\n        \"kind\": \"pastor\",\n        \"name\": \"Ada\",\n        \"email\": \"ada@example.org\",\n        \"phone\": \"\",\n        \"question\": \"Could a pastor call me about forgiveness?\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"kind\": \"pastor\",\n  \"name\": \"Ada\",\n  \"email\": \"ada@example.org\",\n  \"phone\": \"\",\n  \"question\": \"Could a pastor call me about forgiveness?\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/widget/handoff?key=wk_live_8f3a1c9d2b7e\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/widget/messages":{"post":{"description":"Asks a question from a page that embeds the widget. The response is `202` with `status` `pending` and `poll_after_ms`, or `200` with a finished answer when the same question was already answered and reviewed. Poll `GET /v1/public/widget/messages/{message}` for the answer. Visitors are identified by an anonymous `session` string you generate (16 to 128 URL-safe characters) and keep in the browser.\n\nQuestions that need a person (a crisis) are answered with care guidance and a hand-off instead of a model answer. Visitors are rate limited, and a church's widget has a busy ceiling.\n\n**Auth.** None. This route is public.\n\n**Plan.** Needs the widget and Ask features. Each new question counts against the Ask allowance; 429 when the church's allowance is used up for visitors.","operationId":"widgetAsk","parameters":[{"description":"The widget's public site key, created in the console under Widget.","example":"wk_live_8f3a1c9d2b7e","explode":false,"in":"query","name":"key","schema":{"type":"string"}},{"description":"Sent by the browser: the page making the call. It must be in the widget's allowlist.","in":"header","name":"Origin","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"question":"What did we teach about forgiveness?","session":"k3n9x2m8q1w7e5r4t6y0"}}},"schema":{"$ref":"#/components/schemas/WidgetAskInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"widget_answer","data":{"object":"widget_answer","answer":"","blocks":[],"follow_ups":[],"sources":[],"next_steps":[],"conversation_id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","message_id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","status":"pending","poll_after_ms":800}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Ask from the widget."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Please wait a little before asking again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The visitor asked too quickly, or the church's widget is busy."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Ask from the widget","tags":["Widget"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/public/widget/messages?key=wk_live_8f3a1c9d2b7e\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"question\": \"What did we teach about forgiveness?\",\n  \"session\": \"k3n9x2m8q1w7e5r4t6y0\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/widget/messages?key=wk_live_8f3a1c9d2b7e`, {\n  method: \"POST\",\n  headers: {\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"question\": \"What did we teach about forgiveness?\",\n    \"session\": \"k3n9x2m8q1w7e5r4t6y0\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/widget/messages?key=wk_live_8f3a1c9d2b7e\",\n    headers={\n    },\n    json={\n        \"question\": \"What did we teach about forgiveness?\",\n        \"session\": \"k3n9x2m8q1w7e5r4t6y0\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"question\": \"What did we teach about forgiveness?\",\n  \"session\": \"k3n9x2m8q1w7e5r4t6y0\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/widget/messages?key=wk_live_8f3a1c9d2b7e\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the widget and Ask features. Each new question counts against the Ask allowance; 429 when the church's allowance is used up for visitors."}},"/v1/public/widget/messages/{message}":{"get":{"description":"Returns the current state of an answer. `status` is `pending`, `complete` or `failed`. Pass `wait` (seconds) to hold the request open until the answer arrives. Use the same `session` you asked with.\n\n**Auth.** None. This route is public.","operationId":"widgetMessage","parameters":[{"description":"The widget's public site key, created in the console under Widget.","example":"wk_live_8f3a1c9d2b7e","explode":false,"in":"query","name":"key","schema":{"type":"string"}},{"description":"Sent by the browser: the page making the call. It must be in the widget's allowlist.","in":"header","name":"Origin","schema":{"type":"string"}},{"description":"The message id, such as msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"message","required":true,"schema":{"type":"string"}},{"description":"The anonymous visitor id you generated: 16 to 128 URL-safe characters. Use the same one for follow-ups.","example":"k3n9x2m8q1w7e5r4t6y0","explode":false,"in":"query","name":"session","schema":{"pattern":"^[A-Za-z0-9_-]{16,128}$","type":"string"}},{"description":"Seconds to hold the request open until the answer is ready, up to the server's cap.","example":"10","explode":false,"in":"query","name":"wait","schema":{"format":"int64","maximum":20,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"widget_answer","data":{"object":"widget_answer","answer":"Forgiveness is a decision to release a debt, as God released ours. [1]","blocks":[{"type":"paragraph","text":"Pastor Ade taught that forgiving is releasing the debt. [1]","source_refs":[1]}],"follow_ups":["What did we teach about reconciliation?"],"sources":[{"number":1,"title":"Seventy times seven","excerpt":"We forgive because we were forgiven."}],"next_steps":[],"conversation_id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","message_id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","status":"complete"}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Poll a widget answer."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Poll a widget answer","tags":["Widget"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0&wait=10\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0&wait=10`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0&wait=10\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0&wait=10\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/widget/messages/{message}/feedback":{"post":{"description":"Records whether an answer helped. Feedback goes to the church's review queue; it is never used as training data.\n\n**Auth.** None. This route is public.","operationId":"widgetFeedback","parameters":[{"description":"The widget's public site key, created in the console under Widget.","example":"wk_live_8f3a1c9d2b7e","explode":false,"in":"query","name":"key","schema":{"type":"string"}},{"description":"Sent by the browser: the page making the call. It must be in the widget's allowlist.","in":"header","name":"Origin","schema":{"type":"string"}},{"description":"The message id, such as msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"message","required":true,"schema":{"type":"string"}},{"description":"The anonymous visitor id you generated: 16 to 128 URL-safe characters. Use the same one for follow-ups.","example":"k3n9x2m8q1w7e5r4t6y0","explode":false,"in":"query","name":"session","schema":{"pattern":"^[A-Za-z0-9_-]{16,128}$","type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"kind":"helpful"}}},"schema":{"$ref":"#/components/schemas/WidgetFeedbackInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"feedback recorded","data":{"recorded":true}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Rate a widget answer."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Rate a widget answer","tags":["Widget"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/feedback?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"kind\": \"helpful\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/feedback?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0`, {\n  method: \"POST\",\n  headers: {\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"kind\": \"helpful\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/feedback?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0\",\n    headers={\n    },\n    json={\n        \"kind\": \"helpful\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"kind\": \"helpful\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/widget/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/feedback?key=wk_live_8f3a1c9d2b7e&session=k3n9x2m8q1w7e5r4t6y0\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/ask":{"get":{"description":"Tells a page whether to show an Ask box for the church.\n\n**Auth.** None. This route is public.","operationId":"publicAskStatus","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"ask","data":{"object":"ask","church":"grace-chapel","name":"Grace Chapel","enabled":true}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Is public Ask on for a church?."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Is public Ask on for a church?","tags":["Public Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/ask\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/ask`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/ask\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/ask\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]},"post":{"description":"Asks a question from the church's public site, optionally about one published note (`note_slug`). The answer is drawn from the church's published and approved teaching only. Like the widget, the response is pending until you poll `GET /v1/public/{church}/ask/messages/{message}`.\n\n**Auth.** None. This route is public.\n\n**Plan.** Needs the Ask feature; each new question counts against the Ask allowance.","operationId":"publicAskTurn","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"question":"What did we teach about forgiveness?","session":"k3n9x2m8q1w7e5r4t6y0"}}},"schema":{"$ref":"#/components/schemas/PublicAskTurnInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"widget_answer","data":{"object":"widget_answer","answer":"","blocks":[],"follow_ups":[],"sources":[],"next_steps":[],"conversation_id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","message_id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","status":"pending","poll_after_ms":800}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Ask on a church's public page."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Please wait a little before asking again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The visitor asked too quickly."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Ask on a church's public page","tags":["Public Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/public/grace-chapel/ask\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"question\": \"What did we teach about forgiveness?\",\n  \"session\": \"k3n9x2m8q1w7e5r4t6y0\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/ask`, {\n  method: \"POST\",\n  headers: {\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"question\": \"What did we teach about forgiveness?\",\n    \"session\": \"k3n9x2m8q1w7e5r4t6y0\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/ask\",\n    headers={\n    },\n    json={\n        \"question\": \"What did we teach about forgiveness?\",\n        \"session\": \"k3n9x2m8q1w7e5r4t6y0\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"question\": \"What did we teach about forgiveness?\",\n  \"session\": \"k3n9x2m8q1w7e5r4t6y0\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/ask\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the Ask feature; each new question counts against the Ask allowance."}},"/v1/public/{church}/ask/messages/{message}":{"get":{"description":"Returns the current state of an answer from public Ask. Pass `wait` seconds to hold the request open.\n\n**Auth.** None. This route is public.","operationId":"publicAskMessage","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The message id, such as msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"message","required":true,"schema":{"type":"string"}},{"description":"The anonymous visitor id you generated: 16 to 128 URL-safe characters. Use the same one for follow-ups.","example":"k3n9x2m8q1w7e5r4t6y0","explode":false,"in":"query","name":"session","schema":{"pattern":"^[A-Za-z0-9_-]{16,128}$","type":"string"}},{"description":"Seconds to hold the request open until the answer is ready, up to the server's cap.","example":"10","explode":false,"in":"query","name":"wait","schema":{"format":"int64","maximum":20,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"widget_answer","data":{"object":"widget_answer","answer":"Forgiveness is a decision to release a debt, as God released ours. [1]","blocks":[{"type":"paragraph","text":"Pastor Ade taught that forgiving is releasing the debt. [1]","source_refs":[1]}],"follow_ups":["What did we teach about reconciliation?"],"sources":[{"number":1,"title":"Seventy times seven","excerpt":"We forgive because we were forgiven."}],"next_steps":[],"conversation_id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","message_id":"msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","status":"complete"}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Poll a public answer."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Poll a public answer","tags":["Public Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/ask/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?session=k3n9x2m8q1w7e5r4t6y0&wait=10\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/ask/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?session=k3n9x2m8q1w7e5r4t6y0&wait=10`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/ask/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?session=k3n9x2m8q1w7e5r4t6y0&wait=10\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/ask/messages/msg_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012?session=k3n9x2m8q1w7e5r4t6y0&wait=10\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/ask/shares/{token}":{"get":{"description":"A conversation a member shared by link. The token in the link is the only credential: anyone who has it can read the conversation, and the member can revoke it at any time (410 afterwards).\n\n**Auth.** None. This route is public.","operationId":"publicConversationShare","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The share token from the shared link.","example":"shr_k3n9x2","in":"path","name":"token","required":true,"schema":{"maxLength":128,"minLength":12,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"conversation_share","data":{"object":"conversation_share","church":"grace-chapel","title":"Forgiveness","messages":[]}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a conversation shared by link.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}},"X-Robots-Tag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a conversation shared by link","tags":["Public Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/ask/shares/shr_k3n9x2\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/ask/shares/shr_k3n9x2`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/ask/shares/shr_k3n9x2\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/ask/shares/shr_k3n9x2\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/ask/{slug}":{"get":{"description":"A reviewed answer the church published, with its sources and standing: whether a source teaching has since been superseded or retracted.\n\n**Auth.** None. This route is public.","operationId":"publicAsk","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The slug from the share URL.","example":"love-that-waits","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"share","data":{"object":"share","church":"grace-chapel","kind":"answer","slug":"forgiveness","title":"What did we teach about forgiveness?","summary":"Forgiveness is a decision to release a debt.","payload":{"question":"What did we teach about forgiveness?","short":"Forgiveness is a decision to release a debt. [1]","blocks":[{"h":"","p":"Pastor Ade taught that forgiving is releasing the debt. [1]"}],"sources":[{"n":1,"t":"Seventy times seven","by":"Pastor Ade"}],"reviewed":true,"standing":"current"},"published_at":"2026-11-01T12:31:00Z","indexable":true,"unlisted":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a published answer.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a published answer","tags":["Public Ask"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/ask/love-that-waits\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/ask/love-that-waits`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/ask/love-that-waits\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/ask/love-that-waits\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/live":{"get":{"description":"The live status for a church: whether a stream is on and where the captions come from. Cacheable; send `If-None-Match`.\n\n**Auth.** None. This route is public.","operationId":"publicLive","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"live","data":{"object":"live_stream","status":"live","ended":false,"source":"asr","server_now_ms":1793541609000}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Is the church live?.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Is the church live?","tags":["Live"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/live\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/live`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/live\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/live\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/live/captions":{"get":{"description":"Captions as they are spoken. Pass `after` with the last `next_after` you received to get only new captions. Poll about once a second while `status` is `live`.\n\n**Auth.** None. This route is public.","operationId":"publicLiveCaptions","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"Return captions with a sequence greater than this. Send the next_after of the previous response. 0 returns the most recent captions.","example":"0","explode":false,"in":"query","name":"after","schema":{"description":"Return captions with a sequence greater than this. Send the next_after of the previous response. 0 returns the most recent captions.","format":"int64","minimum":0,"type":"integer"}},{"description":"How many items to return, from 1 to 100.","example":"50","explode":false,"in":"query","name":"limit","schema":{"format":"int32","maximum":500,"minimum":1,"type":"integer"}},{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"live captions","data":{"object":"live_captions","status":"live","ended":false,"next_after":2,"source":"asr","server_now_ms":1793541609000,"captions":[{"object":"caption","seq":1,"start_ms":0,"end_ms":2400,"text":"Good morning, church.","ingest_ms":120,"publish_ms":340}]}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read live captions.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read live captions","tags":["Live"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/live/captions?after=0&limit=50\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/live/captions?after=0&limit=50`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/live/captions?after=0&limit=50\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/live/captions?after=0&limit=50\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/notes/{slug}":{"get":{"description":"A published note as the church's public site shows it: sections, verses and questions. Responses are cacheable; send `If-None-Match` to revalidate. `payload.approval_kind` says whether a person (`human`) or the church's automatic approval approved it. 410 means it was published once and has since been retracted.\n\n**Auth.** None. This route is public.","operationId":"publicNote","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The slug from the share URL.","example":"love-that-waits","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"share","data":{"object":"share","church":"grace-chapel","kind":"note","slug":"nothing-can-separate-us","title":"Nothing can separate us","summary":"Nothing in all creation can separate us from the love of God in Christ.","payload":{"approval_kind":"human","translation":"KJV","subtitle":"Sunday note · Romans 8","reading_minutes":6,"standing":"current","source":{"speaker":"Pastor Ade","date":"1 Nov 2026","duration":"40:12"},"sections":[{"id":"who-can-condemn","heading":"Who can condemn?","ref":"Romans 8:34","blocks":[{"type":"p","text":"Paul answers with Christ's death, resurrection and intercession."}]}],"questions":["What are you holding on to this week?"]},"published_at":"2026-11-01T12:31:00Z","updated_at":"2026-11-01T12:31:00Z","indexable":true,"unlisted":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a published note.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a published note","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/notes/love-that-waits\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/notes/love-that-waits`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/notes/love-that-waits\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/notes/love-that-waits\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/notes/{slug}/booklet":{"get":{"description":"The printable booklet of a published note, as a PDF. 404 when the church has not enabled booklets for the note.\n\n**Auth.** None. This route is public.","operationId":"publicNoteBooklet","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The slug from the share URL.","example":"love-that-waits","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"Success. Download a note's booklet."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Download a note's booklet","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/notes/love-that-waits/booklet\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/notes/love-that-waits/booklet`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/notes/love-that-waits/booklet\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/notes/love-that-waits/booklet\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/notes/{slug}/pdf":{"get":{"description":"A published note as a PDF file, laid out for printing or sharing. The response is binary with the content type application/pdf. Responses are cacheable: send If-None-Match with the last ETag to revalidate. Anything that is not published answers 404.\n\n**Auth.** None. This route is public.","operationId":"publicNotePDF","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The slug from the share URL.","example":"love-that-waits","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/pdf":{"schema":{"format":"binary","type":"string"}}},"description":"Success. Download a note as PDF."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Download a note as PDF","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/notes/love-that-waits/pdf\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/notes/love-that-waits/pdf`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/notes/love-that-waits/pdf\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/notes/love-that-waits/pdf\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/s/{alias}":{"get":{"description":"Resolves the short alias used in shared links and returns the share it points to.\n\n**Auth.** None. This route is public.","operationId":"publicShareAlias","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The short alias from the share link.","example":"x7k2q","in":"path","name":"alias","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"share","data":{"object":"share","church":"grace-chapel","kind":"note","slug":"nothing-can-separate-us","title":"Nothing can separate us","summary":"Nothing in all creation can separate us from the love of God in Christ.","payload":{"approval_kind":"human","translation":"KJV","subtitle":"Sunday note · Romans 8","reading_minutes":6,"standing":"current","source":{"speaker":"Pastor Ade","date":"1 Nov 2026","duration":"40:12"},"sections":[{"id":"who-can-condemn","heading":"Who can condemn?","ref":"Romans 8:34","blocks":[{"type":"p","text":"Paul answers with Christ's death, resurrection and intercession."}]}],"questions":["What are you holding on to this week?"]},"published_at":"2026-11-01T12:31:00Z","updated_at":"2026-11-01T12:31:00Z","indexable":true,"unlisted":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a published share by short alias.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a published share by short alias","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/s/x7k2q\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/s/x7k2q`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/s/x7k2q\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/s/x7k2q\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/series/{slug}":{"get":{"description":"A series with its weeks and the published note for each.\n\n**Auth.** None. This route is public.","operationId":"publicSeries","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The slug from the share URL.","example":"love-that-waits","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"share","data":{"object":"share","church":"grace-chapel","kind":"series","slug":"romans-8","title":"Romans 8","summary":"Six weeks in Romans 8.","payload":{"weeks":[{"number":1,"title":"Nothing can separate us","ref":"Romans 8:31-39","state":"read"}]},"published_at":"2026-11-01T12:31:00Z","indexable":true,"unlisted":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a published series.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a published series","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/series/love-that-waits\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/series/love-that-waits`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/series/love-that-waits\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/series/love-that-waits\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/shares":{"get":{"description":"Lists published notes, verses, series and answers for a church, newest first, for feeds and sitemaps. `limit` goes up to 1000 here. Entries carry no payload; read each with its own route.\n\n**Auth.** None. This route is public.","operationId":"publicChurchShares","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"How many items to return, from 1 to 100.","example":"200","explode":false,"in":"query","name":"limit","schema":{"default":200,"format":"int32","maximum":1000,"minimum":1,"type":"integer"}},{"description":"The opaque meta.next_cursor from the previous page.","explode":false,"in":"query","name":"cursor","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"shares","data":[{"object":"share","kind":"note","slug":"nothing-can-separate-us","title":"Nothing can separate us","summary":"Nothing in all creation can separate us from the love of God in Christ.","indexable":true,"published_at":"2026-11-01T12:31:00Z","updated_at":"2026-11-01T12:31:00Z"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. List everything a church has published.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"List everything a church has published","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/shares?limit=200\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/shares?limit=200`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/shares?limit=200\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/shares?limit=200\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/shares/{kind}/{slug}":{"get":{"description":"Reads any published share by `kind` (`note`, `verse`, `answer`, `series` or `subscribe`) and slug. 410 means it was retracted.\n\n**Auth.** None. This route is public.","operationId":"publicShare","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The object kind: song, theme, service_plan or service_record.","example":"note","in":"path","name":"kind","required":true,"schema":{"type":"string"}},{"description":"The slug from the share URL.","example":"love-that-waits","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"share","data":{"object":"share","church":"grace-chapel","kind":"note","slug":"nothing-can-separate-us","title":"Nothing can separate us","summary":"Nothing in all creation can separate us from the love of God in Christ.","payload":{"approval_kind":"human","translation":"KJV","subtitle":"Sunday note · Romans 8","reading_minutes":6,"standing":"current","source":{"speaker":"Pastor Ade","date":"1 Nov 2026","duration":"40:12"},"sections":[{"id":"who-can-condemn","heading":"Who can condemn?","ref":"Romans 8:34","blocks":[{"type":"p","text":"Paul answers with Christ's death, resurrection and intercession."}]}],"questions":["What are you holding on to this week?"]},"published_at":"2026-11-01T12:31:00Z","updated_at":"2026-11-01T12:31:00Z","indexable":true,"unlisted":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a published share by kind and slug.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a published share by kind and slug","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/shares/song/love-that-waits\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/shares/song/love-that-waits`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/shares/song/love-that-waits\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/shares/song/love-that-waits\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/subscribe":{"post":{"description":"Subscribes an email address to the church's updates from your own form. The person gets a confirmation email and is subscribed only after confirming. Every message carries a one-click unsubscribe.\n\n**Auth.** None. This route is public.\n\n**Plan.** The church needs the audience feature.","operationId":"publicSubscribe","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"email":"visitor@example.org","first_name":"Ada","source":"website"}}},"schema":{"$ref":"#/components/schemas/SubscribeInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"subscriber","data":{"id":"0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","status":"pending"}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Subscribe an email address."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Subscribe an email address","tags":["Subscribe"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/public/grace-chapel/subscribe\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"email\": \"visitor@example.org\",\n  \"first_name\": \"Ada\",\n  \"source\": \"website\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/subscribe`, {\n  method: \"POST\",\n  headers: {\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"email\": \"visitor@example.org\",\n    \"first_name\": \"Ada\",\n    \"source\": \"website\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/subscribe\",\n    headers={\n    },\n    json={\n        \"email\": \"visitor@example.org\",\n        \"first_name\": \"Ada\",\n        \"source\": \"website\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"email\": \"visitor@example.org\",\n  \"first_name\": \"Ada\",\n  \"source\": \"website\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/subscribe\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"The church needs the audience feature."}},"/v1/public/{church}/theme":{"get":{"description":"The church's name, brand colours and logo, so an embedded page can match the church.\n\n**Auth.** None. This route is public.","operationId":"publicTheme","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"theme","data":{"object":"theme","church":"grace-chapel","name":"Grace Chapel","brand":"#1f4b99","brand_accent":"#d4a017","logo_url":"https://api.folio.example/v1/public/grace-chapel/logo/3f9a0c1d5b7e2a4c6d8f0a1b3c5d7e9f1a3b5c7d9e0f2a4b6c8d0e1f3a5b7c9d/512.png","logo_sizes":{"32":"https://api.folio.example/v1/public/grace-chapel/logo/3f9a0c1d5b7e2a4c6d8f0a1b3c5d7e9f1a3b5c7d9e0f2a4b6c8d0e1f3a5b7c9d/32.png","128":"https://api.folio.example/v1/public/grace-chapel/logo/3f9a0c1d5b7e2a4c6d8f0a1b3c5d7e9f1a3b5c7d9e0f2a4b6c8d0e1f3a5b7c9d/128.png","512":"https://api.folio.example/v1/public/grace-chapel/logo/3f9a0c1d5b7e2a4c6d8f0a1b3c5d7e9f1a3b5c7d9e0f2a4b6c8d0e1f3a5b7c9d/512.png"}}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a church's public theme.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That church is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The church does not publish."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a church's public theme","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/theme\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/theme`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/theme\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/theme\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/verses/{slug}":{"get":{"description":"A verse or passage page: the King James Version text, how often the church has taught it and by whom, and where its teaching on the passage has changed over time. Scripture is King James Version only.\n\n**Auth.** None. This route is public.","operationId":"publicVerse","parameters":[{"description":"The ETag of the copy you already hold. If it is current the answer is 304 with no body.","in":"header","name":"If-None-Match","schema":{"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}},{"description":"The slug from the share URL.","example":"love-that-waits","in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"share","data":{"object":"share","church":"grace-chapel","kind":"verse","slug":"romans-8-28","title":"Romans 8:28","summary":"God works good through the waiting.","payload":{"reference":"Romans 8:28","translation":"KJV","text":"And we know that all things work together for good to them that love God, to them who are the called according to his purpose.","taught":{"times":4,"preachers":2,"years":3},"teachings":[],"chapter":{"verses":[]}},"published_at":"2026-11-01T12:31:00Z","indexable":true,"unlisted":false}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a published verse page.","headers":{"Cache-Control":{"schema":{"type":"string"}},"ETag":{"schema":{"type":"string"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That share is not available.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Nothing is published at that address."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a published verse page","tags":["Published content"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/verses/love-that-waits\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/verses/love-that-waits`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/verses/love-that-waits\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/verses/love-that-waits\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/public/{church}/widget":{"get":{"description":"The public settings of a church's widget by church slug. Use `GET /v1/public/widget` with a site key when you are embedding the widget on another site.\n\n**Auth.** None. This route is public.","operationId":"publicWidget","parameters":[{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","example":"grace-chapel","in":"path","name":"church","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"widget","data":{"object":"widget","church":"grace-chapel","name":"Grace Chapel"}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read a church's widget settings."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read a church's widget settings","tags":["Widget"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/public/grace-chapel/widget\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/public/grace-chapel/widget`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/public/grace-chapel/widget\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/public/grace-chapel/widget\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/scripture/lookup":{"get":{"description":"Returns the text of a passage and how the church has taught it: how many times, by how many preachers, and the teachings that quote it. `ref` accepts a verse (`John 3:16`), a range (`Romans 8:28-30`) or a whole chapter (`Psalm 23`).\n\nFolio carries the King James Version only. Omit `translation` or pass `KJV`; any other value answers 404.\n\n**Auth.** A church API key. Needs the `scripture:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineScriptureLookup","parameters":[{"description":"A verse, range or chapter such as John 3:16, Romans 8:28-30 or Psalm 23.","example":"Romans 8:28","explode":false,"in":"query","name":"ref","required":true,"schema":{"description":"A verse, range or chapter such as John 3:16, Romans 8:28-30 or Psalm 23.","minLength":1,"type":"string"}},{"description":"Optional. Folio has the King James Version (KJV) only; any other value is not found.","explode":false,"in":"query","name":"translation","schema":{"description":"Optional. Folio has the King James Version (KJV) only; any other value is not found.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"passage","data":{"object":"passage","ref":"Romans 8:28","book":"Romans","chapter":8,"verse_start":28,"verse_end":28,"whole_chapter":false,"translation":"KJV","verses":[{"n":28,"text":"And we know that all things work together for good to them that love God, to them who are the called according to his purpose.","teachings":4}],"taught":{"times":4,"preachers":2,"years":3},"items":[],"items_truncated":false,"summaries":[],"open_tensions":0,"notice":""}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/LookupWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Look up a verse, range or chapter.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That reference or translation was not found.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The reference is not a Bible passage, or the translation is not installed."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["scripture:read"]}],"summary":"Look up a verse, range or chapter","tags":["Scripture"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/scripture/lookup?ref=Romans+8%3A28\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/scripture/lookup?ref=Romans+8%3A28`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/scripture/lookup?ref=Romans+8%3A28\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/scripture/lookup?ref=Romans+8%3A28\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["scripture:read"]}},"/v1/scripture/translations":{"get":{"description":"Lists the installed translations. Today that is the King James Version only, with its edition, licence and attribution.\n\n**Auth.** A church API key. Needs the `scripture:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineScriptureTranslations","parameters":[{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"translations","data":{"object":"translation_list","translations":[{"code":"KJV","name":"King James Version","verses":31102,"edition":"1769 Cambridge","licence":"Public domain","attribution":"King James Version, public domain.","source":"folio"}]}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. List Bible translations.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["scripture:read"]}],"summary":"List Bible translations","tags":["Scripture"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/scripture/translations\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/scripture/translations`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/scripture/translations\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/scripture/translations\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["scripture:read"]}},"/v1/status":{"get":{"description":"The public status of Folio's components and any open incident. `status` is `operational`, `degraded` or `major_outage`.\n\n**Auth.** None. This route is public.","operationId":"statusSurface","responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"status","data":{"object":"status","status":"operational","components":[{"key":"api","name":"API","group":"core","status":"operational"}],"incidents":[]}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Read the service status."},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[],"summary":"Read the service status","tags":["Plans and status"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/status\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/status`, {\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/status\",\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/status\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}]}},"/v1/subscribers":{"get":{"description":"Lists people who subscribed to the church's updates. Email addresses are personal data: keep the key server-side and give it only `audience:read`. The list is a bounded snapshot paged with `limit` and `cursor`.\n\n**Auth.** A church API key. Needs the `audience:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListSubscribers","parameters":[{"description":"Items per page.","explode":false,"in":"query","name":"limit","schema":{"default":50,"description":"Items per page.","format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from meta.next_cursor of the previous page.","explode":false,"in":"query","name":"cursor","schema":{"description":"Opaque cursor from meta.next_cursor of the previous page.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"subscribers","data":[{"id":"sub_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"subscriber","email":"visitor@example.org","status":"confirmed"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyMachineSubscriberWire"}}},"description":"Success. List subscribers.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["audience:read"]}],"summary":"List subscribers","tags":["Audience"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/subscribers\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/subscribers`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/subscribers\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/subscribers\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["audience:read"]}},"/v1/teachings":{"get":{"description":"Lists the church's teachings, newest first, with where each one is in processing. Unlike notes and outputs, keys see teachings in every status, so you can watch an upload progress.\n\nFilter with `status` (comma separated) or search titles, speakers and series with `q`. Pages follow the standard cursor rules; `meta.total` is the number of matching teachings.\n\n**Auth.** A church API key. Needs the `teachings:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListTeachings","parameters":[{"description":"Items per page.","example":"25","explode":false,"in":"query","name":"limit","schema":{"default":25,"description":"Items per page.","format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from meta.next_cursor of the previous page.","explode":false,"in":"query","name":"cursor","schema":{"description":"Opaque cursor from meta.next_cursor of the previous page.","maxLength":400,"type":"string"}},{"description":"Comma separated: ready, failed, queued, processing (everything still working) or awaiting_upload.","example":"ready","explode":false,"in":"query","name":"status","schema":{"description":"Comma separated: ready, failed, queued, processing (everything still working) or awaiting_upload.","maxLength":200,"type":"string"}},{"description":"Words to look for in titles, speakers and series.","explode":false,"in":"query","name":"q","schema":{"description":"Words to look for in titles, speakers and series.","maxLength":200,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"teachings","data":[{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"teaching","title":"Sunday, 1 November: Nothing can separate us","speaker":"Pastor Ade","series":"Romans 8","passage":"Romans 8:31-39","status":"ready","failure_reason":"","duration_seconds":2412,"recorded_at":"2026-11-01T09:00:00Z","created_at":"2026-11-01T10:02:11Z","note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","note_status":"published"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MachineTeachingWire"},"type":"array"},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/ListMeta"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. List teachings.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["teachings:read"]}],"summary":"List teachings","tags":["Teachings"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/teachings?limit=25&status=ready\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/teachings?limit=25&status=ready`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/teachings?limit=25&status=ready\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/teachings?limit=25&status=ready\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["teachings:read"]},"post":{"description":"Starts a teaching and returns a one-time upload ticket. This is step one of adding a recording.\n\n1. Call this with the title, file name and media type. The response holds `url` and `key`.\n2. `PUT` the recording to `url` with the same `Content-Type`. The URL is signed and expires at `expires_at`.\n3. Call `POST /v1/teachings/{teaching}/upload` with `key` to start processing.\n4. Poll `GET /v1/teachings/{teaching}` until `status` is `ready`, or subscribe to `teaching.ready` webhooks.\n\nOnly audio and video are accepted. A teaching you never complete stays in `awaiting_upload`. Send an `Idempotency-Key` so a retry does not create a second teaching.\n\n**Auth.** A church API key. Needs the `media:upload` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Plan.** Needs the API feature and enough transcription hours left in the plan. A plan with no hours left answers 402 `quota_exceeded`. Sandbox churches hold at most 20 teachings and answer 402 when the cap or the test AI budget is reached.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineCreateTeaching","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"title":"Sunday, 1 November: Nothing can separate us","filename":"sunday.mp3","content_type":"audio/mpeg"}}},"schema":{"$ref":"#/components/schemas/MachineCreateTeachingInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"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"}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Create a teaching and get an upload URL.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"402":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This church has used all of its transcription hours for this cycle.","error":{"code":"quota_exceeded","status":402,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The plan's hours are used up, or a sandbox church reached its cap."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"The API is not part of this church's plan.","error":{"code":"not_entitled","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The plan does not include the API, or the key lacks media:upload."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Choose an audio or video recording. That file type is not supported.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The content type is not audio or video, or a field is invalid."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["media:upload"]}],"summary":"Create a teaching and get an upload URL","tags":["Teachings"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/teachings\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: sunday-2026-11-01-create\" \\\n  -d '{\n  \"title\": \"Sunday, 1 November: Nothing can separate us\",\n  \"filename\": \"sunday.mp3\",\n  \"content_type\": \"audio/mpeg\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/teachings`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"sunday-2026-11-01-create\",\n  },\n  body: JSON.stringify({\n    \"title\": \"Sunday, 1 November: Nothing can separate us\",\n    \"filename\": \"sunday.mp3\",\n    \"content_type\": \"audio/mpeg\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/teachings\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n        \"Idempotency-Key\": \"sunday-2026-11-01-create\",\n    },\n    json={\n        \"title\": \"Sunday, 1 November: Nothing can separate us\",\n        \"filename\": \"sunday.mp3\",\n        \"content_type\": \"audio/mpeg\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"title\": \"Sunday, 1 November: Nothing can separate us\",\n  \"filename\": \"sunday.mp3\",\n  \"content_type\": \"audio/mpeg\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/teachings\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"sunday-2026-11-01-create\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the API feature and enough transcription hours left in the plan. A plan with no hours left answers 402 `quota_exceeded`. Sandbox churches hold at most 20 teachings and answer 402 when the cap or the test AI budget is reached.","x-rate-limited":true,"x-required-scopes":["media:upload"]}},"/v1/teachings/{teaching}":{"get":{"description":"Returns one teaching. This is the call to poll after you complete an upload. `status` moves `awaiting_upload`, `queued`, `processing`, then `ready` or `failed`; when it is `failed`, `failure_reason` says why in plain words.\n\nPolling every few seconds is fine. Webhooks (`teaching.ready`, `teaching.failed`) save the polling.\n\n**Auth.** A church API key. Needs the `teachings:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetTeaching","parameters":[{"description":"The teaching id, prefixed tch_.","example":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"teaching","required":true,"schema":{"description":"The teaching id, prefixed tch_.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"teaching","data":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"teaching","title":"Sunday, 1 November: Nothing can separate us","speaker":"Pastor Ade","series":"Romans 8","passage":"Romans 8:31-39","status":"processing","failure_reason":"","duration_seconds":2412,"recorded_at":null,"created_at":"2026-11-01T10:02:11Z","note_id":null,"note_status":"none"}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/MachineTeachingWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Read a teaching.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["teachings:read"]}],"summary":"Read a teaching","tags":["Teachings"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["teachings:read"]}},"/v1/teachings/{teaching}/note":{"get":{"description":"Returns the published note written from a teaching. Until a person (or the church's automatic approval) has published the note, this answers 404 \"This teaching has no published note yet.\" That is expected: Folio shows nothing to members, or to your integration, before review.\n\nSubscribe to `note.published` to know when to call it.\n\n**Auth.** A church API key. Needs the `notes:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetTeachingNote","parameters":[{"description":"The teaching id, prefixed tch_.","example":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"teaching","required":true,"schema":{"description":"The teaching id, prefixed tch_.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"note","data":{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"teaching","name":"Sunday, 1 November: Nothing can separate us"},"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."},{"h":"More than conquerors","body":"Hardship does not cancel God's love; it is where that love is proved."}],"approval_kind":"human","approved_at":"2026-11-01T12:30:00Z","published_at":"2026-11-01T12:31:00Z","created_at":"2026-11-01T10:20:00Z","updated_at":"2026-11-01T12:31:00Z","share_slug":"nothing-can-separate-us","share_path":"/grace-chapel/notes/nothing-can-separate-us","church":"Grace Chapel","speaker":"Pastor Ade"}}}},"schema":{"properties":{"data":{"$ref":"#/components/schemas/MachineNoteWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Read the note for a teaching.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["notes:read"]}],"summary":"Read the note for a teaching","tags":["Notes"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/note\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/note`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/note\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/note\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["notes:read"]}},"/v1/teachings/{teaching}/transcript":{"get":{"description":"Returns the transcript as time-coded segments. The teaching must be `ready`; before that the call answers 404 with a message that says so. Times are milliseconds from the start of the recording. Join the `text` of the segments in order for the full text.\n\n**Auth.** A church API key. Needs the `teachings:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineGetTranscript","parameters":[{"description":"The teaching id, prefixed tch_.","example":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"teaching","required":true,"schema":{"description":"The teaching id, prefixed tch_.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"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."},{"object":"segment","start_ms":6400,"end_ms":13950,"speaker":"Speaker 1","text":"Paul asks who can separate us from the love of Christ."}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MachineSegmentWire"},"type":"array"},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/ListMeta"},"status":{"description":"true for a success.","type":"boolean"}},"required":["status","message","data"],"type":"object"}}},"description":"Success. Read the transcript.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["teachings:read"]}],"summary":"Read the transcript","tags":["Teachings"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/transcript\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/transcript`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/transcript\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/transcript\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["teachings:read"]}},"/v1/teachings/{teaching}/upload":{"post":{"description":"Tells Folio the recording is in storage so it can be transcribed and written up. Send the `key` you got when you created the teaching.\n\nCall it once. A second call answers 409 because the upload was already received. A file that never reached storage, or an empty file, answers 422; upload again and retry. Processing is asynchronous: the teaching moves through `queued` and `processing` to `ready` or `failed`.\n\n**Auth.** A church API key. Needs the `media:upload` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineCompleteUpload","parameters":[{"description":"The teaching id, such as tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"teaching","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"key":"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3"}}},"schema":{"$ref":"#/components/schemas/MachineCompleteUploadInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"upload received","data":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"teaching","name":""}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Finish an upload and start processing.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"This upload was already received.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The upload was already received.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"The file did not reach storage. Upload it again.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The file is empty or did not reach storage."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["media:upload"]}],"summary":"Finish an upload and start processing","tags":["Teachings"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: sunday-2026-11-01-complete\" \\\n  -d '{\n  \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"sunday-2026-11-01-complete\",\n  },\n  body: JSON.stringify({\n    \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n        \"Idempotency-Key\": \"sunday-2026-11-01-complete\",\n    },\n    json={\n        \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"key\": \"originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"sunday-2026-11-01-complete\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["media:upload"]}},"/v1/webhook-endpoints":{"get":{"description":"Lists the church's webhook endpoints with their health: status, consecutive failures and delivery counts over the last 30 days. An endpoint disabled after 20 failures in a row shows `status` `disabled` and a `disabled_reason`.\n\n**Auth.** A church API key. Needs the `webhooks:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListWebhookEndpoints","parameters":[{"description":"Items per page.","explode":false,"in":"query","name":"limit","schema":{"default":50,"description":"Items per page.","format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor from meta.next_cursor of the previous page.","explode":false,"in":"query","name":"cursor","schema":{"description":"Opaque cursor from meta.next_cursor of the previous page.","type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_endpoints","data":[{"id":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"webhook_endpoint","name":"Sunday pipeline","url":"https://hooks.example.org/folio","event_types":["teaching.ready","note.published"],"mode":"live","status":"active","api_version":"2026-12-01","child_scope":"none","church_ids":[],"consecutive_failures":0,"last_success_at":"2026-11-01T12:31:04Z","last_failure_at":null,"created_at":"2026-10-20T09:00:00Z","stats":{"delivered":42,"failed":1,"pending":0,"window_days":30,"last_delivery_at":"2026-11-01T12:31:04Z"}}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyWebhookEndpointWire"}}},"description":"Success. List webhook endpoints.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:read"]}],"summary":"List webhook endpoints","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/webhook-endpoints\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:read"]},"post":{"description":"Registers a public https URL to receive events. `event_types` takes types from the event catalogue, or `*` for every event including ones added later. The response carries the signing `secret` (`whsec_…`) once; store it, you cannot read it again. Use it to verify the `webhook-signature` header.\n\n`mode` is `live` or `test`. Partner keys can set `child_scope` to also receive customer churches' events (`all`) or only some (`selected` with `church_ids`).\n\nUse `POST /v1/webhook-endpoints/{endpoint}/test` right after to check your receiver.\n\n**Auth.** A church API key. Needs the `webhooks:write` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Plan.** Needs the API feature. Sandbox churches cannot receive outbound webhooks.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineCreateWebhookEndpoint","parameters":[{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"name":"Sunday pipeline","url":"https://hooks.example.org/folio","event_types":["teaching.ready","note.published"],"mode":"live"}}},"schema":{"$ref":"#/components/schemas/MachineEndpointCreateInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_endpoint","data":{"endpoint":{"id":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"webhook_endpoint","name":"Sunday pipeline","url":"https://hooks.example.org/folio","event_types":["teaching.ready","note.published"],"mode":"live","status":"active","api_version":"2026-12-01","child_scope":"none","church_ids":[],"consecutive_failures":0,"last_success_at":"2026-11-01T12:31:04Z","last_failure_at":null,"created_at":"2026-10-20T09:00:00Z","stats":{"delivered":42,"failed":1,"pending":0,"window_days":30,"last_delivery_at":"2026-11-01T12:31:04Z"}},"secret":"whsec_3f9d1c7a0b2e4f68a5d4c3b2a1908f7e"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyMachineEndpointCreatedWire"}}},"description":"Success. Create a webhook endpoint.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That URL must be a public https endpoint.","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The URL is not a public https endpoint, or an event type is not recognised."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:write"]}],"summary":"Create a webhook endpoint","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/webhook-endpoints\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Idempotency-Key: endpoint-sunday-pipeline\" \\\n  -d '{\n  \"name\": \"Sunday pipeline\",\n  \"url\": \"https://hooks.example.org/folio\",\n  \"event_types\": [\n    \"teaching.ready\",\n    \"note.published\"\n  ],\n  \"mode\": \"live\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n    \"Idempotency-Key\": \"endpoint-sunday-pipeline\",\n  },\n  body: JSON.stringify({\n    \"name\": \"Sunday pipeline\",\n    \"url\": \"https://hooks.example.org/folio\",\n    \"event_types\": [\n      \"teaching.ready\",\n      \"note.published\"\n    ],\n    \"mode\": \"live\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n        \"Idempotency-Key\": \"endpoint-sunday-pipeline\",\n    },\n    json={\n        \"name\": \"Sunday pipeline\",\n        \"url\": \"https://hooks.example.org/folio\",\n        \"event_types\": [\n            \"teaching.ready\",\n            \"note.published\",\n        ],\n        \"mode\": \"live\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"name\": \"Sunday pipeline\",\n  \"url\": \"https://hooks.example.org/folio\",\n  \"event_types\": [\n    \"teaching.ready\",\n    \"note.published\"\n  ],\n  \"mode\": \"live\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\trequest.Header.Set(\"Idempotency-Key\", \"endpoint-sunday-pipeline\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-plan":"Needs the API feature. Sandbox churches cannot receive outbound webhooks.","x-rate-limited":true,"x-required-scopes":["webhooks:write"]}},"/v1/webhook-endpoints/{endpoint}":{"delete":{"description":"Deletes an endpoint. Deliveries already queued for it are dropped. This cannot be undone; to pause an endpoint, update its events instead.\n\n**Auth.** A church API key. Needs the `webhooks:write` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineDeleteWebhookEndpoint","parameters":[{"description":"The webhook endpoint id, such as whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"endpoint","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_endpoint","data":{"id":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","deleted":true}}}},"schema":{"$ref":"#/components/schemas/TypedBodyMachineEndpointDeletedWire"}}},"description":"Success. Delete a webhook endpoint.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:write"]}],"summary":"Delete a webhook endpoint","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X DELETE \"$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012`, {\n  method: \"DELETE\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"DELETE\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"DELETE\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:write"]},"patch":{"description":"Changes an endpoint's name, URL, events, mode or church scope. The URL is checked again. The signing secret does not change unless you rotate it. Sending a full body is the safest: fields you leave out are cleared to their defaults.\n\n**Auth.** A church API key. Needs the `webhooks:write` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineUpdateWebhookEndpoint","parameters":[{"description":"The webhook endpoint id, such as whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"endpoint","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"name":"Sunday pipeline","url":"https://hooks.example.org/folio","event_types":["teaching.ready","teaching.failed","note.published"],"filter":{},"shape":{},"dedupe":{},"mode":"live"}}},"schema":{"$ref":"#/components/schemas/MachineEndpointUpdateInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_endpoint","data":{"id":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"webhook_endpoint","name":"Sunday pipeline","url":"https://hooks.example.org/folio","event_types":["teaching.ready","note.published"],"mode":"live","status":"active","api_version":"2026-12-01","child_scope":"none","church_ids":[],"consecutive_failures":0,"last_success_at":"2026-11-01T12:31:04Z","last_failure_at":null,"created_at":"2026-10-20T09:00:00Z","stats":{"delivered":42,"failed":1,"pending":0,"window_days":30,"last_delivery_at":"2026-11-01T12:31:04Z"}}}}},"schema":{"$ref":"#/components/schemas/TypedBodyWebhookEndpointWire"}}},"description":"Success. Update a webhook endpoint.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:write"]}],"summary":"Update a webhook endpoint","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X PATCH \"$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"name\": \"Sunday pipeline\",\n  \"url\": \"https://hooks.example.org/folio\",\n  \"event_types\": [\n    \"teaching.ready\",\n    \"teaching.failed\",\n    \"note.published\"\n  ],\n  \"filter\": {},\n  \"shape\": {},\n  \"dedupe\": {},\n  \"mode\": \"live\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012`, {\n  method: \"PATCH\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"name\": \"Sunday pipeline\",\n    \"url\": \"https://hooks.example.org/folio\",\n    \"event_types\": [\n      \"teaching.ready\",\n      \"teaching.failed\",\n      \"note.published\"\n    ],\n    \"filter\": {},\n    \"shape\": {},\n    \"dedupe\": {},\n    \"mode\": \"live\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"PATCH\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    json={\n        \"name\": \"Sunday pipeline\",\n        \"url\": \"https://hooks.example.org/folio\",\n        \"event_types\": [\n            \"teaching.ready\",\n            \"teaching.failed\",\n            \"note.published\",\n        ],\n        \"filter\": {},\n        \"shape\": {},\n        \"dedupe\": {},\n        \"mode\": \"live\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"name\": \"Sunday pipeline\",\n  \"url\": \"https://hooks.example.org/folio\",\n  \"event_types\": [\n    \"teaching.ready\",\n    \"teaching.failed\",\n    \"note.published\"\n  ],\n  \"filter\": {},\n  \"shape\": {},\n  \"dedupe\": {},\n  \"mode\": \"live\"\n}`)\n\trequest, err := http.NewRequest(\"PATCH\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:write"]}},"/v1/webhook-endpoints/{endpoint}/deliveries":{"get":{"description":"Lists deliveries to an endpoint, newest first. Filter by `status` (pending, delivered, failed, skipped), by `event` type, or by customer `church` for partner endpoints. A failed delivery shows its `last_error` and, while retries remain, `next_attempt_at`.\n\n**Auth.** A church API key. Needs the `webhooks:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListWebhookDeliveries","parameters":[{"description":"The webhook endpoint id, such as whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"endpoint","required":true,"schema":{"type":"string"}},{"description":"Only deliveries in this status: pending, delivered, failed or skipped.","example":"failed","explode":false,"in":"query","name":"status","schema":{"enum":["","pending","delivered","failed","skipped"],"type":"string"}},{"description":"Only deliveries of this event type, such as note.published.","explode":false,"in":"query","name":"event","schema":{"maxLength":120,"type":"string"}},{"description":"The church slug, such as grace-chapel. For partner routes, the customer church id (org_) or slug.","explode":false,"in":"query","name":"church","schema":{"maxLength":80,"type":"string"}},{"description":"How many items to return, from 1 to 100.","explode":false,"in":"query","name":"limit","schema":{"format":"int64","maximum":100,"minimum":1,"type":"integer"}},{"description":"The opaque meta.next_cursor from the previous page.","explode":false,"in":"query","name":"cursor","schema":{"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_deliveries","data":[{"id":"whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"webhook_delivery","event_id":"0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","event_type":"note.published","status":"failed","attempts":3,"origin":"live","last_error":"HTTP 500","created_at":"2026-11-01T12:31:00Z","next_attempt_at":"2026-11-01T13:31:00Z","delivered_at":null}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyDeliveryRow"}}},"description":"Success. List recent deliveries.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:read"]}],"summary":"List recent deliveries","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries?status=failed\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries?status=failed`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries?status=failed\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries?status=failed\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:read"]}},"/v1/webhook-endpoints/{endpoint}/deliveries/{delivery}/attempts":{"get":{"description":"Lists every attempt for a delivery: the exact request (headers with the signature shortened, and the body for 30 days), your receiver's status, latency and the first 2 KB of its answer. Use it to debug a failing receiver.\n\n**Auth.** A church API key. Needs the `webhooks:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineListWebhookAttempts","parameters":[{"description":"The webhook endpoint id, such as whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"endpoint","required":true,"schema":{"type":"string"}},{"description":"The delivery id, such as whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"delivery","required":true,"schema":{"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_attempts","data":[{"id":"wha_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"webhook_attempt","attempt_number":1,"trigger":"auto","response_code":500,"response_body":"internal error","duration_ms":212,"error_code":"","error_message":"","request_headers":{"webhook-id":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","webhook-signature":"v1,K5oZ…"},"request_body":{"type":"note.published"},"signed_at":"2026-11-01T12:31:00Z","created_at":"2026-11-01T12:31:00Z"}],"meta":{"request_id":"req_b337770ecebe03b03a88a8998b59263d","has_next":false,"has_prev":false}}}},"schema":{"$ref":"#/components/schemas/TypedListBodyMachineAttemptWire"}}},"description":"Success. Read what was sent and what came back.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:read"]}],"summary":"Read what was sent and what came back","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/attempts\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/attempts`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/attempts\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/attempts\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:read"]}},"/v1/webhook-endpoints/{endpoint}/deliveries/{delivery}/replay":{"post":{"description":"Sends the event again as a new delivery with the same payload. Use it after you fix a receiver. The replay has a new `webhook-id`, so a receiver that deduplicates on it will process it again.\n\n**Auth.** A church API key. Needs the `webhooks:write` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineReplayWebhookDelivery","parameters":[{"description":"The webhook endpoint id, such as whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"endpoint","required":true,"schema":{"type":"string"}},{"description":"The delivery id, such as whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"delivery","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_delivery","data":{"id":"whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","status":"pending"}}}},"schema":{"$ref":"#/components/schemas/Envelope"}}},"description":"Success. Send a delivery again.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:write"]}],"summary":"Send a delivery again","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/replay\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/replay`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/replay\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/deliveries/whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/replay\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:write"]}},"/v1/webhook-endpoints/{endpoint}/rotate":{"post":{"description":"Issues a new signing secret, returned once. Both secrets sign each message for `prev_expires_in_hours` (24), so deploy the new secret to your receiver and nothing is dropped. Verify with either during the overlap.\n\n**Auth.** A church API key. Needs the `webhooks:write` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineRotateWebhookEndpoint","parameters":[{"description":"The webhook endpoint id, such as whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"endpoint","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_endpoint","data":{"id":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","secret":"whsec_9a8b7c6d5e4f30211203f4e5d6c7b8a9","prev_expires_in_hours":24}}}},"schema":{"$ref":"#/components/schemas/TypedBodyMachineEndpointRotatedWire"}}},"description":"Success. Rotate the signing secret.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:write"]}],"summary":"Rotate the signing secret","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/rotate\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Idempotency-Key: rotate-2026-11\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/rotate`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Idempotency-Key\": \"rotate-2026-11\",\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/rotate\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n        \"Idempotency-Key\": \"rotate-2026-11\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/rotate\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Idempotency-Key\", \"rotate-2026-11\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:write"]}},"/v1/webhook-endpoints/{endpoint}/test":{"post":{"description":"Sends a real, signed test delivery to the endpoint and reports what your receiver answered. The delivery carries the header `Folio-Test: true`. Pass `event_type` to test a specific event's payload; the default is a generic test event.\n\n**Auth.** A church API key. Needs the `webhooks:write` scope, or a wildcard that includes it (`machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineTestWebhookEndpoint","parameters":[{"description":"The webhook endpoint id, such as whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012.","example":"whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"path","name":"endpoint","required":true,"schema":{"type":"string"}},{"description":"Makes a retry safe. The same key with the same body replays the first response for 24 hours; the same key with a different body returns 422; a duplicate that is still running returns 409 with Retry-After. Responses that carry a one-time secret are not replayed.","example":"sunday-2026-11-01-upload","in":"header","name":"Idempotency-Key","schema":{"maxLength":255,"type":"string"}},{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A typical request","value":{"event_type":"note.published"}}},"schema":{"$ref":"#/components/schemas/MachineEndpointTestInputBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_delivery","data":{"delivery":"whd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","delivered":true,"status":200,"test":true}}}},"schema":{"$ref":"#/components/schemas/TypedBodyMachineEndpointTestWire"}}},"description":"Success. Send a signed test event.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:write"]}],"summary":"Send a signed test event","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X POST \"$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/test\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"event_type\": \"note.published\"\n}'"},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/test`, {\n  method: \"POST\",\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    \"event_type\": \"note.published\"\n  }),\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"POST\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/test\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    json={\n        \"event_type\": \"note.published\",\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n)\n\nfunc main() {\n\tpayload := strings.NewReader(`{\n  \"event_type\": \"note.published\"\n}`)\n\trequest, err := http.NewRequest(\"POST\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/test\", payload)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:write"]}},"/v1/webhook-event-types":{"get":{"description":"Lists every event type Folio can send, grouped by area, with a description, the fields it carries and an example payload. The catalogue is generated from the code that sends events, so it is always current. The same catalogue is readable without a key at `GET /v1/public/webhook-events`.\n\n**Auth.** A church API key. Needs the `webhooks:read` scope, or a wildcard that includes it (`machine:read`, `machine:*`, `*` on a partner key). A partner key can call it for a customer church by sending `X-Folio-Church`.\n\n**Limits.** Responses carry `RateLimit-Limit` and `RateLimit-Remaining`; a `429` carries `Retry-After`.","operationId":"machineWebhookEventCatalogue","parameters":[{"description":"Partner keys only: run this call as one of your customer churches (its org_ id or slug). The church must be one of yours, the key must be allowed to act for it, and plan checks run against that church.","example":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","in":"header","name":"X-Folio-Church","schema":{"maxLength":80,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"examples":{"default":{"summary":"A typical response","value":{"status":true,"message":"webhook_event_catalogue","data":{"groups":[{"key":"note","label":"Notes","events":[{"object":"webhook_event_type","type":"note.published","group":"note","group_label":"Notes","description":"A note was published to its share page.","source":"notes","fields":[{"name":"teaching_id","type":"string","required":true,"description":"The teaching this note belongs to."}],"example":{"type":"note.published"}}]}],"total":1,"all":"*"}}}},"schema":{"$ref":"#/components/schemas/TypedBodyEventCatalogueWire"}}},"description":"Success. Read the event catalogue.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}}}},"400":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"the page cursor is not valid","error":{"code":"invalid_argument","status":400,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The request could not be read."},"401":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key is not valid or has expired.","error":{"code":"unauthenticated","status":401,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The key or session is missing, invalid or expired."},"403":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That API key does not have the required scope.","error":{"code":"permission_denied","status":403,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The credential lacks the scope, the church is suspended, the feature is not in the plan, or the address is not allowed."},"404":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"That item is not in this church.","error":{"code":"not_found","status":404,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"The resource is not in this church."},"409":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A request with this Idempotency-Key is still running.","error":{"code":"conflict","status":409,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Conflict, including a duplicate Idempotency-Key still being processed.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"422":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"A field is not valid.","error":{"code":"validation","status":422,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"A field failed validation, or an Idempotency-Key was reused with a different body."},"429":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Too many requests. Wait before trying again.","error":{"code":"rate_limited","status":429,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Rate limited. Wait Retry-After seconds.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}}},"500":{"content":{"application/json":{"examples":{"default":{"summary":"An error","value":{"status":false,"message":"Something went wrong. Quote the request id to support.","error":{"code":"internal","status":500,"request_id":"req_b337770ecebe03b03a88a8998b59263d"}}}},"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Something went wrong. Quote error.request_id."},"default":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}},"description":"Error"}},"security":[{"bearerAuth":["webhooks:read"]}],"summary":"Read the event catalogue","tags":["Webhook endpoints"],"x-codeSamples":[{"lang":"Shell","label":"curl","source":"curl -X GET \"$FOLIO_API_URL/v1/webhook-event-types\" \\\n  -H \"Authorization: Bearer $FOLIO_API_KEY\""},{"lang":"JavaScript","label":"JavaScript","source":"const response = await fetch(`${process.env.FOLIO_API_URL}/v1/webhook-event-types`, {\n  headers: {\n    \"Authorization\": `Bearer ${process.env.FOLIO_API_KEY}`,\n  },\n});\nconst result = await response.json();"},{"lang":"Python","label":"Python","source":"import os\nimport requests\n\nresponse = requests.request(\n    \"GET\",\n    os.environ[\"FOLIO_API_URL\"] + \"/v1/webhook-event-types\",\n    headers={\n        \"Authorization\": \"Bearer \" + os.environ[\"FOLIO_API_KEY\"],\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\nresult = response.json()"},{"lang":"Go","label":"Go","source":"package main\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n)\n\nfunc main() {\n\trequest, err := http.NewRequest(\"GET\", os.Getenv(\"FOLIO_API_URL\")+\"/v1/webhook-event-types\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trequest.Header.Set(\"Authorization\", \"Bearer \" + os.Getenv(\"FOLIO_API_KEY\"))\n\tresponse, err := http.DefaultClient.Do(request)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer response.Body.Close()\n\tresult, _ := io.ReadAll(response.Body)\n\t_ = result\n}"}],"x-rate-limited":true,"x-required-scopes":["webhooks:read"]}}},"webhooks":{"access.changed":{"post":{"description":"A source or feature was switched on or off for the church, by Folio or by the church's owner.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `access.changed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_access_changed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A access.changed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"change":"enabled","changed_by":"folio","id":"acc_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"source:vimeo","object":"access_change","occurred_at":"2026-10-13T09:12:10Z","role":"editor"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"access.changed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"change":{"description":"What happened: enabled, disabled, reset, restricted or unrestricted.","type":"string"},"changed_by":{"description":"Who changed it: folio, or church when the church changed its own rules.","type":"string"},"id":{"description":"The change id.","type":"string"},"key":{"description":"The source or feature that changed, such as source:vimeo or feature:ask.","type":"string"},"object":{"description":"Always access_change.","enum":["access_change"],"type":"string"},"occurred_at":{"description":"When it changed.","format":"date-time","type":"string"},"role":{"description":"The role it applies to, when role-specific.","type":"string"}},"required":["id","object","key","change","changed_by","occurred_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"access.changed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"access.changed","tags":["Webhook events"],"x-group":"Access"}},"api_key.created":{"post":{"description":"An API key was created. The secret is never included.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `api_key.created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_api_key_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A api_key.created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"church_ids":[],"created_at":"2026-10-13T09:12:10Z","created_by":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"expires_at":"2026-11-13T09:12:10Z","id":"key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","last4":"a91c","mode":"live","name":"CRM sync","object":"api_key","partner":false,"prefix":"folio_live_3f9d","rate_limit_per_minute":600,"revoked_at":"2026-10-13T09:12:10Z","scopes":["teachings:read","notes:read"]}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"api_key.created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The customer church the key belongs to, on partner keys."},"church_ids":{"description":"Customer churches a partner key may act for; empty means all.","items":{"description":"One value.","type":"string"},"type":"array"},"created_at":{"description":"When it was created.","format":"date-time","type":"string"},"created_by":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The team member who created it."},"expires_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the key stops working."},"id":{"description":"The API key id.","type":"string"},"last4":{"description":"The last four characters of the key.","type":"string"},"mode":{"description":"live or test.","enum":["live","test"],"type":"string"},"name":{"description":"The label given to the key.","type":"string"},"object":{"description":"Always api_key.","enum":["api_key"],"type":"string"},"partner":{"description":"True for a partner key.","type":"boolean"},"prefix":{"description":"The visible start of the key.","type":"string"},"rate_limit_per_minute":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The per-minute limit, null for the plan default."},"revoked_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was revoked."},"scopes":{"description":"The permissions it was given.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","name","prefix","last4","mode","scopes","partner","church_ids","rate_limit_per_minute","expires_at","revoked_at","created_by","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"api_key.created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"api_key.created","tags":["Webhook events"],"x-group":"API keys"}},"api_key.revoked":{"post":{"description":"An API key was revoked.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `api_key.revoked`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_api_key_revoked","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A api_key.revoked event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"church_ids":[],"created_at":"2026-10-13T09:12:10Z","created_by":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"expires_at":"2026-11-13T09:12:10Z","id":"key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","last4":"a91c","mode":"live","name":"CRM sync","object":"api_key","partner":false,"prefix":"folio_live_3f9d","rate_limit_per_minute":600,"revoked_at":"2026-10-13T09:12:10Z","scopes":["teachings:read","notes:read"]},"previous_attributes":{"revoked_at":"2026-10-12T09:12:10Z"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"api_key.revoked"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The customer church the key belongs to, on partner keys."},"church_ids":{"description":"Customer churches a partner key may act for; empty means all.","items":{"description":"One value.","type":"string"},"type":"array"},"created_at":{"description":"When it was created.","format":"date-time","type":"string"},"created_by":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The team member who created it."},"expires_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the key stops working."},"id":{"description":"The API key id.","type":"string"},"last4":{"description":"The last four characters of the key.","type":"string"},"mode":{"description":"live or test.","enum":["live","test"],"type":"string"},"name":{"description":"The label given to the key.","type":"string"},"object":{"description":"Always api_key.","enum":["api_key"],"type":"string"},"partner":{"description":"True for a partner key.","type":"boolean"},"prefix":{"description":"The visible start of the key.","type":"string"},"rate_limit_per_minute":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The per-minute limit, null for the plan default."},"revoked_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was revoked."},"scopes":{"description":"The permissions it was given.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","name","prefix","last4","mode","scopes","partner","church_ids","rate_limit_per_minute","expires_at","revoked_at","created_by","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: revoked_at.","type":"object"}},"type":"object"},"type":{"const":"api_key.revoked"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"api_key.revoked","tags":["Webhook events"],"x-group":"API keys"}},"audience.campaign_sent":{"post":{"description":"A campaign was sent to its recipients.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `audience.campaign_sent`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_audience_campaign_sent","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A audience.campaign_sent event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"channel":"email","created_at":"2026-10-13T09:12:10Z","id":"cmp_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Sunday recap","object":"campaign","recipients":1240,"scheduled_at":"2026-10-13T09:12:10Z","sent_at":"2026-10-13T09:12:10Z","status":"sent"},"previous_attributes":{"status":"draft"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"audience.campaign_sent"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"channel":{"description":"How it was sent.","enum":["email","sms","whatsapp"],"type":"string"},"created_at":{"description":"When it was created.","format":"date-time","type":"string"},"id":{"description":"The campaign id.","type":"string"},"name":{"description":"The label the church gave the campaign.","type":"string"},"object":{"description":"Always campaign.","enum":["campaign"],"type":"string"},"recipients":{"description":"How many people it went to.","type":"integer"},"scheduled_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was scheduled for."},"sent_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was sent."},"status":{"description":"Where the send stands.","enum":["draft","scheduled","sending","sent","cancelled"],"type":"string"}},"required":["id","object","name","channel","status","recipients","scheduled_at","sent_at","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"audience.campaign_sent"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"audience.campaign_sent","tags":["Webhook events"],"x-group":"Audience"}},"audience.subscriber_confirmed":{"post":{"description":"A subscriber confirmed their email address.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `audience.subscriber_confirmed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_audience_subscriber_confirmed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A audience.subscriber_confirmed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"channels":[{"channel":"email","state":"active"}],"confirmed_at":"2026-10-13T09:12:10Z","created_at":"2026-10-13T09:12:10Z","id":"sub_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","object":"subscriber","source":"website","status":"active","unsubscribed_at":"2026-10-13T09:12:10Z"},"previous_attributes":{"status":"pending"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"audience.subscriber_confirmed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"channels":{"description":"Consent state per channel. No addresses are sent.","items":{"additionalProperties":false,"description":"One channel.","properties":{"channel":{"description":"The channel.","enum":["email","sms","whatsapp"],"type":"string"},"state":{"description":"Where consent stands: none, pending, active, granted, bounced, complained or unsubscribed.","type":"string"}},"required":["channel","state"],"type":"object"},"type":"array"},"confirmed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they confirmed."},"created_at":{"description":"When they signed up.","format":"date-time","type":"string"},"id":{"description":"The subscriber id.","type":"string"},"language":{"description":"The language they receive.","type":"string"},"object":{"description":"Always subscriber.","enum":["subscriber"],"type":"string"},"source":{"description":"How they signed up.","type":"string"},"status":{"description":"The subscriber state.","enum":["pending","active","bounced","complained","unsubscribed","erased"],"type":"string"},"unsubscribed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they opted out."}},"required":["id","object","status","language","source","channels","created_at","confirmed_at","unsubscribed_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"audience.subscriber_confirmed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"audience.subscriber_confirmed","tags":["Webhook events"],"x-group":"Audience"}},"audience.subscriber_erased":{"post":{"description":"A subscriber's personal data was erased on request. Only the id and consent history remain.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `audience.subscriber_erased`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_audience_subscriber_erased","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A audience.subscriber_erased event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"channels":[{"channel":"email","state":"active"}],"confirmed_at":"2026-10-13T09:12:10Z","created_at":"2026-10-13T09:12:10Z","id":"sub_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","object":"subscriber","source":"website","status":"active","unsubscribed_at":"2026-10-13T09:12:10Z"},"previous_attributes":{"status":"pending"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"audience.subscriber_erased"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"channels":{"description":"Consent state per channel. No addresses are sent.","items":{"additionalProperties":false,"description":"One channel.","properties":{"channel":{"description":"The channel.","enum":["email","sms","whatsapp"],"type":"string"},"state":{"description":"Where consent stands: none, pending, active, granted, bounced, complained or unsubscribed.","type":"string"}},"required":["channel","state"],"type":"object"},"type":"array"},"confirmed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they confirmed."},"created_at":{"description":"When they signed up.","format":"date-time","type":"string"},"id":{"description":"The subscriber id.","type":"string"},"language":{"description":"The language they receive.","type":"string"},"object":{"description":"Always subscriber.","enum":["subscriber"],"type":"string"},"source":{"description":"How they signed up.","type":"string"},"status":{"description":"The subscriber state.","enum":["pending","active","bounced","complained","unsubscribed","erased"],"type":"string"},"unsubscribed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they opted out."}},"required":["id","object","status","language","source","channels","created_at","confirmed_at","unsubscribed_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"audience.subscriber_erased"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"audience.subscriber_erased","tags":["Webhook events"],"x-group":"Audience"}},"audience.subscriber_unsubscribed":{"post":{"description":"A subscriber opted out.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `audience.subscriber_unsubscribed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_audience_subscriber_unsubscribed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A audience.subscriber_unsubscribed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"channels":[{"channel":"email","state":"active"}],"confirmed_at":"2026-10-13T09:12:10Z","created_at":"2026-10-13T09:12:10Z","id":"sub_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","object":"subscriber","source":"website","status":"active","unsubscribed_at":"2026-10-13T09:12:10Z"},"previous_attributes":{"status":"pending"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"audience.subscriber_unsubscribed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"channels":{"description":"Consent state per channel. No addresses are sent.","items":{"additionalProperties":false,"description":"One channel.","properties":{"channel":{"description":"The channel.","enum":["email","sms","whatsapp"],"type":"string"},"state":{"description":"Where consent stands: none, pending, active, granted, bounced, complained or unsubscribed.","type":"string"}},"required":["channel","state"],"type":"object"},"type":"array"},"confirmed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they confirmed."},"created_at":{"description":"When they signed up.","format":"date-time","type":"string"},"id":{"description":"The subscriber id.","type":"string"},"language":{"description":"The language they receive.","type":"string"},"object":{"description":"Always subscriber.","enum":["subscriber"],"type":"string"},"source":{"description":"How they signed up.","type":"string"},"status":{"description":"The subscriber state.","enum":["pending","active","bounced","complained","unsubscribed","erased"],"type":"string"},"unsubscribed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they opted out."}},"required":["id","object","status","language","source","channels","created_at","confirmed_at","unsubscribed_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"audience.subscriber_unsubscribed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"audience.subscriber_unsubscribed","tags":["Webhook events"],"x-group":"Audience"}},"billing.invoice_paid":{"post":{"description":"An invoice was paid.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.invoice_paid`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_invoice_paid","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.invoice_paid event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"amount_due_minor":0,"amount_paid_minor":7900,"church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","issued_at":"2026-10-13T09:12:10Z","last_payment_error":{"attempted_at":"2026-10-13T09:12:10Z","code":"card_declined","message":"The card was declined."},"lines":{"data":[{"amount_minor":6583,"description":"Church (month)"}],"has_more":false,"object":"list","url":"/v1/billing/invoices"},"number":"INV-0192F7A8-1A2B3C4D","object":"invoice","payment_method":{"brand":"visa","exp_month":8,"exp_year":2029,"id":"pm_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"card","last4":"4242","object":"payment_method"},"period_end":"2026-11-13T09:12:10Z","period_start":"2026-10-13T09:12:10Z","provider":"stripe","provider_url":"","refunds":{"data":[{"amount_minor":7900,"created_at":"2026-10-13T09:12:10Z","id":"ref_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"refund","status":"succeeded"}],"has_more":false,"object":"list","url":"/v1/billing/invoices"},"status":"paid","status_transitions":{"due_at":"2026-11-13T09:12:10Z","paid_at":"2026-10-13T09:12:10Z"},"subscription":{"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"subscription","status":"active"},"subtotal_minor":6583,"tax_label":"VAT 20%","tax_lines":{"data":[{"amount_minor":1317,"inclusive":false,"jurisdiction":"GB","label":"VAT 20%","rate_bps":2000,"tax_type":"vat","treatment":"charge"}],"has_more":false,"object":"list","url":"/v1/billing/invoices"},"tax_minor":1317,"tax_notes":["Seller tax number: GB123456789"],"total":{"amount_minor":7900,"currency":"USD"},"total_minor":7900},"previous_attributes":{"amount_due_minor":-1,"amount_paid_minor":7899,"status":"draft"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.invoice_paid"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"amount_due_minor":{"description":"What is still owed.","type":"integer"},"amount_paid_minor":{"description":"What has been paid.","type":"integer"},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it was created.","format":"date-time","type":"string"},"currency":{"description":"The ISO 4217 currency code in upper case.","type":"string"},"id":{"description":"The invoice id.","type":"string"},"issued_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was issued."},"last_payment_error":{"anyOf":[{"additionalProperties":false,"properties":{"attempted_at":{"description":"When the charge was tried.","format":"date-time","type":"string"},"code":{"description":"A short code such as card_declined.","type":"string"},"message":{"description":"A plain message safe to show.","type":"string"}},"required":["code","message","attempted_at"],"type":"object"},{"type":"null"}],"description":"Why the latest charge failed."},"lines":{"additionalProperties":false,"description":"What was charged.","properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookInvoiceLine"},"maxItems":25,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing/invoices","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"number":{"description":"The invoice number.","type":"string"},"object":{"description":"Always invoice.","enum":["invoice"],"type":"string"},"payment_method":{"anyOf":[{"$ref":"#/components/schemas/WebhookPaymentMethodSummary"},{"type":"null"}],"description":"The method that paid or was tried. Only a brand and last four digits."},"period_end":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the billed period ends."},"period_start":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the billed period starts."},"provider":{"description":"The payment provider key.","type":"string"},"provider_url":{"description":"A hosted invoice page, empty when none.","type":"string"},"refunds":{"additionalProperties":false,"description":"Refunds issued against it.","properties":{"data":{"items":{"additionalProperties":false,"description":"One refund.","properties":{"amount_minor":{"description":"The refunded amount.","type":"integer"},"created_at":{"description":"When it was issued.","format":"date-time","type":"string"},"id":{"description":"The refund id.","type":"string"},"object":{"description":"Always refund.","enum":["refund"],"type":"string"},"status":{"description":"The refund status.","type":"string"}},"required":["id","object","amount_minor","status","created_at"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing/invoices","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"status":{"description":"The invoice status.","enum":["draft","open","paid","void","uncollectible"],"type":"string"},"status_transitions":{"additionalProperties":false,"description":"When the invoice reached each state.","properties":{"due_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When payment is due."},"paid_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was paid."}},"required":["due_at","paid_at"],"type":"object"},"subscription":{"anyOf":[{"$ref":"#/components/schemas/WebhookSubscriptionRef"},{"type":"null"}],"description":"The subscription it bills."},"subtotal_minor":{"description":"The total before tax in the smallest currency unit.","type":"integer"},"tax_label":{"description":"How the tax is described on the invoice.","type":"string"},"tax_lines":{"additionalProperties":false,"description":"The taxes charged.","properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookTaxLine"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing/invoices","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"tax_minor":{"description":"The tax in the smallest currency unit.","type":"integer"},"tax_notes":{"description":"Legal notes printed with the tax, such as a reverse-charge statement.","items":{"description":"One value.","type":"string"},"type":"array"},"total":{"$ref":"#/components/schemas/WebhookMoney","description":"The invoice total as an amount with its currency."},"total_minor":{"description":"The total in the smallest currency unit.","type":"integer"}},"required":["id","object","number","status","currency","subtotal_minor","tax_minor","tax_label","tax_notes","total_minor","amount_paid_minor","amount_due_minor","total","lines","tax_lines","issued_at","period_start","period_end","status_transitions","subscription","church","payment_method","last_payment_error","refunds","provider","provider_url","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status, amount_paid_minor, amount_due_minor.","type":"object"}},"type":"object"},"type":{"const":"billing.invoice_paid"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.invoice_paid","tags":["Webhook events"],"x-group":"Billing"}},"billing.payment_failed":{"post":{"description":"A charge did not go through. Nothing is paused yet. last_payment_error says why.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.payment_failed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_payment_failed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.payment_failed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"amount_due_minor":0,"amount_paid_minor":7900,"church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","issued_at":"2026-10-13T09:12:10Z","last_payment_error":{"attempted_at":"2026-10-13T09:12:10Z","code":"card_declined","message":"The card was declined."},"lines":{"data":[{"amount_minor":6583,"description":"Church (month)"}],"has_more":false,"object":"list","url":"/v1/billing/invoices"},"number":"INV-0192F7A8-1A2B3C4D","object":"invoice","payment_method":{"brand":"visa","exp_month":8,"exp_year":2029,"id":"pm_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"card","last4":"4242","object":"payment_method"},"period_end":"2026-11-13T09:12:10Z","period_start":"2026-10-13T09:12:10Z","provider":"stripe","provider_url":"","refunds":{"data":[{"amount_minor":7900,"created_at":"2026-10-13T09:12:10Z","id":"ref_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"refund","status":"succeeded"}],"has_more":false,"object":"list","url":"/v1/billing/invoices"},"status":"paid","status_transitions":{"due_at":"2026-11-13T09:12:10Z","paid_at":"2026-10-13T09:12:10Z"},"subscription":{"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"subscription","status":"active"},"subtotal_minor":6583,"tax_label":"VAT 20%","tax_lines":{"data":[{"amount_minor":1317,"inclusive":false,"jurisdiction":"GB","label":"VAT 20%","rate_bps":2000,"tax_type":"vat","treatment":"charge"}],"has_more":false,"object":"list","url":"/v1/billing/invoices"},"tax_minor":1317,"tax_notes":["Seller tax number: GB123456789"],"total":{"amount_minor":7900,"currency":"USD"},"total_minor":7900}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.payment_failed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"amount_due_minor":{"description":"What is still owed.","type":"integer"},"amount_paid_minor":{"description":"What has been paid.","type":"integer"},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it was created.","format":"date-time","type":"string"},"currency":{"description":"The ISO 4217 currency code in upper case.","type":"string"},"id":{"description":"The invoice id.","type":"string"},"issued_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was issued."},"last_payment_error":{"anyOf":[{"additionalProperties":false,"properties":{"attempted_at":{"description":"When the charge was tried.","format":"date-time","type":"string"},"code":{"description":"A short code such as card_declined.","type":"string"},"message":{"description":"A plain message safe to show.","type":"string"}},"required":["code","message","attempted_at"],"type":"object"},{"type":"null"}],"description":"Why the latest charge failed."},"lines":{"additionalProperties":false,"description":"What was charged.","properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookInvoiceLine"},"maxItems":25,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing/invoices","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"number":{"description":"The invoice number.","type":"string"},"object":{"description":"Always invoice.","enum":["invoice"],"type":"string"},"payment_method":{"anyOf":[{"$ref":"#/components/schemas/WebhookPaymentMethodSummary"},{"type":"null"}],"description":"The method that paid or was tried. Only a brand and last four digits."},"period_end":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the billed period ends."},"period_start":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the billed period starts."},"provider":{"description":"The payment provider key.","type":"string"},"provider_url":{"description":"A hosted invoice page, empty when none.","type":"string"},"refunds":{"additionalProperties":false,"description":"Refunds issued against it.","properties":{"data":{"items":{"additionalProperties":false,"description":"One refund.","properties":{"amount_minor":{"description":"The refunded amount.","type":"integer"},"created_at":{"description":"When it was issued.","format":"date-time","type":"string"},"id":{"description":"The refund id.","type":"string"},"object":{"description":"Always refund.","enum":["refund"],"type":"string"},"status":{"description":"The refund status.","type":"string"}},"required":["id","object","amount_minor","status","created_at"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing/invoices","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"status":{"description":"The invoice status.","enum":["draft","open","paid","void","uncollectible"],"type":"string"},"status_transitions":{"additionalProperties":false,"description":"When the invoice reached each state.","properties":{"due_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When payment is due."},"paid_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was paid."}},"required":["due_at","paid_at"],"type":"object"},"subscription":{"anyOf":[{"$ref":"#/components/schemas/WebhookSubscriptionRef"},{"type":"null"}],"description":"The subscription it bills."},"subtotal_minor":{"description":"The total before tax in the smallest currency unit.","type":"integer"},"tax_label":{"description":"How the tax is described on the invoice.","type":"string"},"tax_lines":{"additionalProperties":false,"description":"The taxes charged.","properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookTaxLine"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing/invoices","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"tax_minor":{"description":"The tax in the smallest currency unit.","type":"integer"},"tax_notes":{"description":"Legal notes printed with the tax, such as a reverse-charge statement.","items":{"description":"One value.","type":"string"},"type":"array"},"total":{"$ref":"#/components/schemas/WebhookMoney","description":"The invoice total as an amount with its currency."},"total_minor":{"description":"The total in the smallest currency unit.","type":"integer"}},"required":["id","object","number","status","currency","subtotal_minor","tax_minor","tax_label","tax_notes","total_minor","amount_paid_minor","amount_due_minor","total","lines","tax_lines","issued_at","period_start","period_end","status_transitions","subscription","church","payment_method","last_payment_error","refunds","provider","provider_url","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"billing.payment_failed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.payment_failed","tags":["Webhook events"],"x-group":"Billing"}},"billing.quota_reached":{"post":{"description":"Usage for a meter reached what the plan includes this period. Sent once per meter per period.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.quota_reached`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_quota_reached","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.quota_reached event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"consumed":40,"id":"hours","included":40,"meter":"hours","object":"usage_meter","percent_used":100,"period":{"end":"2026-11-13T09:12:10Z","start":"2026-10-13T09:12:10Z"},"remaining":0}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.quota_reached"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church the usage belongs to."},"consumed":{"description":"What has been used this period.","type":"integer"},"id":{"description":"The meter key.","type":"string"},"included":{"description":"What the plan includes, with credits.","type":"integer"},"meter":{"description":"The meter key: hours, generations, ask_messages and so on.","type":"string"},"object":{"description":"Always usage_meter.","enum":["usage_meter"],"type":"string"},"percent_used":{"description":"The share of the allowance used.","type":"integer"},"period":{"additionalProperties":false,"description":"The billing period.","properties":{"end":{"description":"The last moment of the period.","format":"date-time","type":"string"},"start":{"description":"The first day of the period.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"remaining":{"description":"What is left this period, 0 once reached.","type":"integer"}},"required":["id","object","meter","included","consumed","remaining","percent_used","period","church"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"billing.quota_reached"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.quota_reached","tags":["Webhook events"],"x-group":"Billing"}},"billing.subscription_canceled":{"post":{"description":"A cancellation was scheduled. cancel_at is when access ends.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.subscription_canceled`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_subscription_canceled","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.subscription_canceled event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"cancel_at":"2026-11-13T09:12:10Z","canceled_at":"2026-10-13T09:12:10Z","church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","current_period":{"end":"2026-11-13T09:12:10Z","start":"2026-10-13T09:12:10Z"},"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","interval":"month","items":{"data":[{"description":"Church (month)","object":"subscription_item","price":{"amount_minor":7900,"currency":"USD"},"quantity":1}],"has_more":false,"object":"list","url":"/v1/billing"},"latest_invoice":{"id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","number":"INV-0192F7A8-1A2B3C4D","object":"invoice","status":"paid"},"object":"subscription","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"status":"active","trial":{"days_left":7,"ended_at":"2026-10-13T09:12:10Z","ends_at":"2026-11-13T09:12:10Z","kind":"trial","outcome":"expired","started_at":"2026-10-13T09:12:10Z"}},"previous_attributes":{"cancel_at":"2026-10-12T09:12:10Z"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.subscription_canceled"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"cancel_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When access ends after a scheduled cancellation."},"canceled_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was canceled."},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it started.","format":"date-time","type":"string"},"currency":{"description":"The billing currency.","type":"string"},"current_period":{"additionalProperties":false,"description":"The period being billed.","properties":{"end":{"description":"When it ends.","format":"date-time","type":"string"},"start":{"description":"When the period began.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"id":{"description":"The subscription id.","type":"string"},"interval":{"description":"month or year.","enum":["month","year"],"type":"string"},"items":{"additionalProperties":false,"description":"The plan and any add-ons.","properties":{"data":{"items":{"additionalProperties":false,"description":"One billed item.","properties":{"description":{"description":"What is billed.","type":"string"},"object":{"description":"Always subscription_item.","enum":["subscription_item"],"type":"string"},"price":{"$ref":"#/components/schemas/WebhookMoney","description":"The recurring price."},"quantity":{"description":"How many.","type":"integer"}},"required":["object","description","price","quantity"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"latest_invoice":{"anyOf":[{"$ref":"#/components/schemas/WebhookInvoiceRef"},{"type":"null"}],"description":"The most recent invoice."},"object":{"description":"Always subscription.","enum":["subscription"],"type":"string"},"plan":{"$ref":"#/components/schemas/WebhookPlanRef","description":"The plan it is on."},"status":{"description":"The subscription status.","enum":["trialing","active","past_due","grace","paused","canceled","expired","scheduled"],"type":"string"},"trial":{"anyOf":[{"additionalProperties":false,"properties":{"days_left":{"description":"Days remaining, 0 once ended.","type":"integer"},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended, null while running."},"ends_at":{"description":"When it ends.","format":"date-time","type":"string"},"kind":{"description":"trial or pilot.","enum":["trial","pilot"],"type":"string"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How it ended: expired, ended_early or converted; null while running."},"started_at":{"description":"When it began.","format":"date-time","type":"string"}},"required":["kind","started_at","ends_at","ended_at","outcome","days_left"],"type":"object"},{"type":"null"}],"description":"Trial or pilot details, present while or after one ran."}},"required":["id","object","status","interval","currency","plan","church","items","current_period","trial","cancel_at","canceled_at","latest_invoice","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: cancel_at.","type":"object"}},"type":"object"},"type":{"const":"billing.subscription_canceled"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.subscription_canceled","tags":["Webhook events"],"x-group":"Billing"}},"billing.subscription_changed":{"post":{"description":"The plan changed, an add-on was bought, or a cancellation was undone. previous_attributes holds what changed.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.subscription_changed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_subscription_changed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.subscription_changed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"cancel_at":"2026-11-13T09:12:10Z","canceled_at":"2026-10-13T09:12:10Z","church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","current_period":{"end":"2026-11-13T09:12:10Z","start":"2026-10-13T09:12:10Z"},"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","interval":"month","items":{"data":[{"description":"Church (month)","object":"subscription_item","price":{"amount_minor":7900,"currency":"USD"},"quantity":1}],"has_more":false,"object":"list","url":"/v1/billing"},"latest_invoice":{"id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","number":"INV-0192F7A8-1A2B3C4D","object":"invoice","status":"paid"},"object":"subscription","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"status":"active","trial":{"days_left":7,"ended_at":"2026-10-13T09:12:10Z","ends_at":"2026-11-13T09:12:10Z","kind":"trial","outcome":"expired","started_at":"2026-10-13T09:12:10Z"}},"previous_attributes":{"cancel_at":"2026-10-12T09:12:10Z","interval":"year","items":{"data":[{"description":"Church (month)","object":"subscription_item","price":{"amount_minor":7900,"currency":"USD"},"quantity":1}],"has_more":false,"object":"list","url":"/v1/billing"},"plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"status":"trialing"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.subscription_changed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"cancel_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When access ends after a scheduled cancellation."},"canceled_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was canceled."},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it started.","format":"date-time","type":"string"},"currency":{"description":"The billing currency.","type":"string"},"current_period":{"additionalProperties":false,"description":"The period being billed.","properties":{"end":{"description":"When it ends.","format":"date-time","type":"string"},"start":{"description":"When the period began.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"id":{"description":"The subscription id.","type":"string"},"interval":{"description":"month or year.","enum":["month","year"],"type":"string"},"items":{"additionalProperties":false,"description":"The plan and any add-ons.","properties":{"data":{"items":{"additionalProperties":false,"description":"One billed item.","properties":{"description":{"description":"What is billed.","type":"string"},"object":{"description":"Always subscription_item.","enum":["subscription_item"],"type":"string"},"price":{"$ref":"#/components/schemas/WebhookMoney","description":"The recurring price."},"quantity":{"description":"How many.","type":"integer"}},"required":["object","description","price","quantity"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"latest_invoice":{"anyOf":[{"$ref":"#/components/schemas/WebhookInvoiceRef"},{"type":"null"}],"description":"The most recent invoice."},"object":{"description":"Always subscription.","enum":["subscription"],"type":"string"},"plan":{"$ref":"#/components/schemas/WebhookPlanRef","description":"The plan it is on."},"status":{"description":"The subscription status.","enum":["trialing","active","past_due","grace","paused","canceled","expired","scheduled"],"type":"string"},"trial":{"anyOf":[{"additionalProperties":false,"properties":{"days_left":{"description":"Days remaining, 0 once ended.","type":"integer"},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended, null while running."},"ends_at":{"description":"When it ends.","format":"date-time","type":"string"},"kind":{"description":"trial or pilot.","enum":["trial","pilot"],"type":"string"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How it ended: expired, ended_early or converted; null while running."},"started_at":{"description":"When it began.","format":"date-time","type":"string"}},"required":["kind","started_at","ends_at","ended_at","outcome","days_left"],"type":"object"},{"type":"null"}],"description":"Trial or pilot details, present while or after one ran."}},"required":["id","object","status","interval","currency","plan","church","items","current_period","trial","cancel_at","canceled_at","latest_invoice","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: plan, interval, status, cancel_at, items.","type":"object"}},"type":"object"},"type":{"const":"billing.subscription_changed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.subscription_changed","tags":["Webhook events"],"x-group":"Billing"}},"billing.subscription_started":{"post":{"description":"A paid plan or trial began.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.subscription_started`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_subscription_started","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.subscription_started event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"cancel_at":"2026-11-13T09:12:10Z","canceled_at":"2026-10-13T09:12:10Z","church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","current_period":{"end":"2026-11-13T09:12:10Z","start":"2026-10-13T09:12:10Z"},"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","interval":"month","items":{"data":[{"description":"Church (month)","object":"subscription_item","price":{"amount_minor":7900,"currency":"USD"},"quantity":1}],"has_more":false,"object":"list","url":"/v1/billing"},"latest_invoice":{"id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","number":"INV-0192F7A8-1A2B3C4D","object":"invoice","status":"paid"},"object":"subscription","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"status":"active","trial":{"days_left":7,"ended_at":"2026-10-13T09:12:10Z","ends_at":"2026-11-13T09:12:10Z","kind":"trial","outcome":"expired","started_at":"2026-10-13T09:12:10Z"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.subscription_started"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"cancel_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When access ends after a scheduled cancellation."},"canceled_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was canceled."},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it started.","format":"date-time","type":"string"},"currency":{"description":"The billing currency.","type":"string"},"current_period":{"additionalProperties":false,"description":"The period being billed.","properties":{"end":{"description":"When it ends.","format":"date-time","type":"string"},"start":{"description":"When the period began.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"id":{"description":"The subscription id.","type":"string"},"interval":{"description":"month or year.","enum":["month","year"],"type":"string"},"items":{"additionalProperties":false,"description":"The plan and any add-ons.","properties":{"data":{"items":{"additionalProperties":false,"description":"One billed item.","properties":{"description":{"description":"What is billed.","type":"string"},"object":{"description":"Always subscription_item.","enum":["subscription_item"],"type":"string"},"price":{"$ref":"#/components/schemas/WebhookMoney","description":"The recurring price."},"quantity":{"description":"How many.","type":"integer"}},"required":["object","description","price","quantity"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"latest_invoice":{"anyOf":[{"$ref":"#/components/schemas/WebhookInvoiceRef"},{"type":"null"}],"description":"The most recent invoice."},"object":{"description":"Always subscription.","enum":["subscription"],"type":"string"},"plan":{"$ref":"#/components/schemas/WebhookPlanRef","description":"The plan it is on."},"status":{"description":"The subscription status.","enum":["trialing","active","past_due","grace","paused","canceled","expired","scheduled"],"type":"string"},"trial":{"anyOf":[{"additionalProperties":false,"properties":{"days_left":{"description":"Days remaining, 0 once ended.","type":"integer"},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended, null while running."},"ends_at":{"description":"When it ends.","format":"date-time","type":"string"},"kind":{"description":"trial or pilot.","enum":["trial","pilot"],"type":"string"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How it ended: expired, ended_early or converted; null while running."},"started_at":{"description":"When it began.","format":"date-time","type":"string"}},"required":["kind","started_at","ends_at","ended_at","outcome","days_left"],"type":"object"},{"type":"null"}],"description":"Trial or pilot details, present while or after one ran."}},"required":["id","object","status","interval","currency","plan","church","items","current_period","trial","cancel_at","canceled_at","latest_invoice","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"billing.subscription_started"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.subscription_started","tags":["Webhook events"],"x-group":"Billing"}},"billing.trial_ended":{"post":{"description":"A trial or pilot ended without a paid plan. The church keeps its content and moves to read-only.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.trial_ended`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_trial_ended","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.trial_ended event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"cancel_at":"2026-11-13T09:12:10Z","canceled_at":"2026-10-13T09:12:10Z","church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","current_period":{"end":"2026-11-13T09:12:10Z","start":"2026-10-13T09:12:10Z"},"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","interval":"month","items":{"data":[{"description":"Church (month)","object":"subscription_item","price":{"amount_minor":7900,"currency":"USD"},"quantity":1}],"has_more":false,"object":"list","url":"/v1/billing"},"latest_invoice":{"id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","number":"INV-0192F7A8-1A2B3C4D","object":"invoice","status":"paid"},"object":"subscription","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"status":"active","trial":{"days_left":7,"ended_at":"2026-10-13T09:12:10Z","ends_at":"2026-11-13T09:12:10Z","kind":"trial","outcome":"expired","started_at":"2026-10-13T09:12:10Z"}},"previous_attributes":{"status":"trialing"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.trial_ended"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"cancel_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When access ends after a scheduled cancellation."},"canceled_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was canceled."},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it started.","format":"date-time","type":"string"},"currency":{"description":"The billing currency.","type":"string"},"current_period":{"additionalProperties":false,"description":"The period being billed.","properties":{"end":{"description":"When it ends.","format":"date-time","type":"string"},"start":{"description":"When the period began.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"id":{"description":"The subscription id.","type":"string"},"interval":{"description":"month or year.","enum":["month","year"],"type":"string"},"items":{"additionalProperties":false,"description":"The plan and any add-ons.","properties":{"data":{"items":{"additionalProperties":false,"description":"One billed item.","properties":{"description":{"description":"What is billed.","type":"string"},"object":{"description":"Always subscription_item.","enum":["subscription_item"],"type":"string"},"price":{"$ref":"#/components/schemas/WebhookMoney","description":"The recurring price."},"quantity":{"description":"How many.","type":"integer"}},"required":["object","description","price","quantity"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"latest_invoice":{"anyOf":[{"$ref":"#/components/schemas/WebhookInvoiceRef"},{"type":"null"}],"description":"The most recent invoice."},"object":{"description":"Always subscription.","enum":["subscription"],"type":"string"},"plan":{"$ref":"#/components/schemas/WebhookPlanRef","description":"The plan it is on."},"status":{"description":"The subscription status.","enum":["trialing","active","past_due","grace","paused","canceled","expired","scheduled"],"type":"string"},"trial":{"anyOf":[{"additionalProperties":false,"properties":{"days_left":{"description":"Days remaining, 0 once ended.","type":"integer"},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended, null while running."},"ends_at":{"description":"When it ends.","format":"date-time","type":"string"},"kind":{"description":"trial or pilot.","enum":["trial","pilot"],"type":"string"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How it ended: expired, ended_early or converted; null while running."},"started_at":{"description":"When it began.","format":"date-time","type":"string"}},"required":["kind","started_at","ends_at","ended_at","outcome","days_left"],"type":"object"},{"type":"null"}],"description":"Trial or pilot details, present while or after one ran."}},"required":["id","object","status","interval","currency","plan","church","items","current_period","trial","cancel_at","canceled_at","latest_invoice","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"billing.trial_ended"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.trial_ended","tags":["Webhook events"],"x-group":"Billing"}},"billing.trial_ending":{"post":{"description":"A trial or pilot has 7, 3 or 1 days left. Sent once for each of those marks. trial.days_left says which.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.trial_ending`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_trial_ending","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.trial_ending event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"cancel_at":"2026-11-13T09:12:10Z","canceled_at":"2026-10-13T09:12:10Z","church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","current_period":{"end":"2026-11-13T09:12:10Z","start":"2026-10-13T09:12:10Z"},"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","interval":"month","items":{"data":[{"description":"Church (month)","object":"subscription_item","price":{"amount_minor":7900,"currency":"USD"},"quantity":1}],"has_more":false,"object":"list","url":"/v1/billing"},"latest_invoice":{"id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","number":"INV-0192F7A8-1A2B3C4D","object":"invoice","status":"paid"},"object":"subscription","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"status":"active","trial":{"days_left":7,"ended_at":"2026-10-13T09:12:10Z","ends_at":"2026-11-13T09:12:10Z","kind":"trial","outcome":"expired","started_at":"2026-10-13T09:12:10Z"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.trial_ending"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"cancel_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When access ends after a scheduled cancellation."},"canceled_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was canceled."},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it started.","format":"date-time","type":"string"},"currency":{"description":"The billing currency.","type":"string"},"current_period":{"additionalProperties":false,"description":"The period being billed.","properties":{"end":{"description":"When it ends.","format":"date-time","type":"string"},"start":{"description":"When the period began.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"id":{"description":"The subscription id.","type":"string"},"interval":{"description":"month or year.","enum":["month","year"],"type":"string"},"items":{"additionalProperties":false,"description":"The plan and any add-ons.","properties":{"data":{"items":{"additionalProperties":false,"description":"One billed item.","properties":{"description":{"description":"What is billed.","type":"string"},"object":{"description":"Always subscription_item.","enum":["subscription_item"],"type":"string"},"price":{"$ref":"#/components/schemas/WebhookMoney","description":"The recurring price."},"quantity":{"description":"How many.","type":"integer"}},"required":["object","description","price","quantity"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"latest_invoice":{"anyOf":[{"$ref":"#/components/schemas/WebhookInvoiceRef"},{"type":"null"}],"description":"The most recent invoice."},"object":{"description":"Always subscription.","enum":["subscription"],"type":"string"},"plan":{"$ref":"#/components/schemas/WebhookPlanRef","description":"The plan it is on."},"status":{"description":"The subscription status.","enum":["trialing","active","past_due","grace","paused","canceled","expired","scheduled"],"type":"string"},"trial":{"anyOf":[{"additionalProperties":false,"properties":{"days_left":{"description":"Days remaining, 0 once ended.","type":"integer"},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended, null while running."},"ends_at":{"description":"When it ends.","format":"date-time","type":"string"},"kind":{"description":"trial or pilot.","enum":["trial","pilot"],"type":"string"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How it ended: expired, ended_early or converted; null while running."},"started_at":{"description":"When it began.","format":"date-time","type":"string"}},"required":["kind","started_at","ends_at","ended_at","outcome","days_left"],"type":"object"},{"type":"null"}],"description":"Trial or pilot details, present while or after one ran."}},"required":["id","object","status","interval","currency","plan","church","items","current_period","trial","cancel_at","canceled_at","latest_invoice","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"billing.trial_ending"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.trial_ending","tags":["Webhook events"],"x-group":"Billing"}},"billing.trial_started":{"post":{"description":"A trial or pilot began. No card is needed.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `billing.trial_started`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_billing_trial_started","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A billing.trial_started event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"cancel_at":"2026-11-13T09:12:10Z","canceled_at":"2026-10-13T09:12:10Z","church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"created_at":"2026-10-13T09:12:10Z","currency":"USD","current_period":{"end":"2026-11-13T09:12:10Z","start":"2026-10-13T09:12:10Z"},"id":"subs_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","interval":"month","items":{"data":[{"description":"Church (month)","object":"subscription_item","price":{"amount_minor":7900,"currency":"USD"},"quantity":1}],"has_more":false,"object":"list","url":"/v1/billing"},"latest_invoice":{"id":"inv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","number":"INV-0192F7A8-1A2B3C4D","object":"invoice","status":"paid"},"object":"subscription","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"status":"active","trial":{"days_left":7,"ended_at":"2026-10-13T09:12:10Z","ends_at":"2026-11-13T09:12:10Z","kind":"trial","outcome":"expired","started_at":"2026-10-13T09:12:10Z"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"billing.trial_started"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"cancel_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When access ends after a scheduled cancellation."},"canceled_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was canceled."},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church it belongs to."},"created_at":{"description":"When it started.","format":"date-time","type":"string"},"currency":{"description":"The billing currency.","type":"string"},"current_period":{"additionalProperties":false,"description":"The period being billed.","properties":{"end":{"description":"When it ends.","format":"date-time","type":"string"},"start":{"description":"When the period began.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"id":{"description":"The subscription id.","type":"string"},"interval":{"description":"month or year.","enum":["month","year"],"type":"string"},"items":{"additionalProperties":false,"description":"The plan and any add-ons.","properties":{"data":{"items":{"additionalProperties":false,"description":"One billed item.","properties":{"description":{"description":"What is billed.","type":"string"},"object":{"description":"Always subscription_item.","enum":["subscription_item"],"type":"string"},"price":{"$ref":"#/components/schemas/WebhookMoney","description":"The recurring price."},"quantity":{"description":"How many.","type":"integer"}},"required":["object","description","price","quantity"],"type":"object"},"maxItems":10,"type":"array"},"has_more":{"description":"True when more items exist than this page holds; fetch them from url.","type":"boolean"},"object":{"const":"list"},"url":{"const":"/v1/billing","description":"The API path that lists every item.","type":"string"}},"required":["object","data","has_more","url"],"type":"object"},"latest_invoice":{"anyOf":[{"$ref":"#/components/schemas/WebhookInvoiceRef"},{"type":"null"}],"description":"The most recent invoice."},"object":{"description":"Always subscription.","enum":["subscription"],"type":"string"},"plan":{"$ref":"#/components/schemas/WebhookPlanRef","description":"The plan it is on."},"status":{"description":"The subscription status.","enum":["trialing","active","past_due","grace","paused","canceled","expired","scheduled"],"type":"string"},"trial":{"anyOf":[{"additionalProperties":false,"properties":{"days_left":{"description":"Days remaining, 0 once ended.","type":"integer"},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended, null while running."},"ends_at":{"description":"When it ends.","format":"date-time","type":"string"},"kind":{"description":"trial or pilot.","enum":["trial","pilot"],"type":"string"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"How it ended: expired, ended_early or converted; null while running."},"started_at":{"description":"When it began.","format":"date-time","type":"string"}},"required":["kind","started_at","ends_at","ended_at","outcome","days_left"],"type":"object"},{"type":"null"}],"description":"Trial or pilot details, present while or after one ran."}},"required":["id","object","status","interval","currency","plan","church","items","current_period","trial","cancel_at","canceled_at","latest_invoice","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"billing.trial_started"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"billing.trial_started","tags":["Webhook events"],"x-group":"Billing"}},"care.alert_created":{"post":{"description":"A care alert was raised. The message itself is never included; open the alert in Folio.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `care.alert_created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_care_alert_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A care.alert_created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"acknowledged_at":"2026-10-13T09:12:10Z","assigned_to":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"category":"suicide_self_harm","created_at":"2026-10-13T09:12:10Z","detection":"lexicon","id":"car_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"care_alert","status":"open","surface":"widget","urgency":"high"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"care.alert_created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"acknowledged_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When a team member acknowledged it."},"assigned_to":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The team member handling it."},"category":{"description":"The kind of concern.","type":"string"},"created_at":{"description":"When it was raised.","format":"date-time","type":"string"},"detection":{"description":"How it was found.","enum":["lexicon","model","uncertain","classifier_unavailable"],"type":"string"},"id":{"description":"The care alert id.","type":"string"},"object":{"description":"Always care_alert.","enum":["care_alert"],"type":"string"},"status":{"description":"Where handling stands.","enum":["open","acknowledged","handled"],"type":"string"},"surface":{"description":"Where it was raised.","enum":["widget","staff","api","member_app","whatsapp"],"type":"string"},"urgency":{"description":"How soon it needs attention.","enum":["low","elevated","medium","high","critical"],"type":"string"}},"required":["id","object","urgency","category","surface","detection","status","assigned_to","created_at","acknowledged_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"care.alert_created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"care.alert_created","tags":["Webhook events"],"x-group":"Care"}},"connection.connected":{"post":{"description":"A storage account such as Google Drive was connected. Tokens are never included.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `connection.connected`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_connection_connected","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A connection.connected event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"account":"default","created_at":"2026-10-13T09:12:10Z","id":"con_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","last_synced_at":"2026-10-13T09:12:10Z","object":"connection","provider":"gdrive","scopes":["drive.readonly"],"status":"active"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"connection.connected"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"account":{"description":"The account label inside Folio.","type":"string"},"created_at":{"description":"When it was connected.","format":"date-time","type":"string"},"id":{"description":"The connection id.","type":"string"},"last_synced_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When files last synced."},"object":{"description":"Always connection.","enum":["connection"],"type":"string"},"provider":{"description":"The provider key.","type":"string"},"scopes":{"description":"The permissions granted at the provider.","items":{"description":"One value.","type":"string"},"type":"array"},"status":{"description":"The connection state, such as active or disconnected.","type":"string"}},"required":["id","object","provider","account","status","scopes","last_synced_at","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"connection.connected"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"connection.connected","tags":["Webhook events"],"x-group":"Connections"}},"connection.disconnected":{"post":{"description":"A storage account was disconnected.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `connection.disconnected`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_connection_disconnected","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A connection.disconnected event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"account":"default","created_at":"2026-10-13T09:12:10Z","id":"con_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","last_synced_at":"2026-10-13T09:12:10Z","object":"connection","provider":"gdrive","scopes":["drive.readonly"],"status":"active"},"previous_attributes":{"status":"Previous active"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"connection.disconnected"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"account":{"description":"The account label inside Folio.","type":"string"},"created_at":{"description":"When it was connected.","format":"date-time","type":"string"},"id":{"description":"The connection id.","type":"string"},"last_synced_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When files last synced."},"object":{"description":"Always connection.","enum":["connection"],"type":"string"},"provider":{"description":"The provider key.","type":"string"},"scopes":{"description":"The permissions granted at the provider.","items":{"description":"One value.","type":"string"},"type":"array"},"status":{"description":"The connection state, such as active or disconnected.","type":"string"}},"required":["id","object","provider","account","status","scopes","last_synced_at","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"connection.disconnected"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"connection.disconnected","tags":["Webhook events"],"x-group":"Connections"}},"conversation.handoff_created":{"post":{"description":"A visitor or team member asked for a person to follow up on a conversation. The question and contact details are never included.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `conversation.handoff_created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_conversation_handoff_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A conversation.handoff_created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"assigned_to":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"conversation":{"id":"conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"conversation","surface":"widget"},"conversation_shared":false,"created_at":"2026-10-13T09:12:10Z","id":"hof_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"pastor","object":"handoff","reachable_by":["email"],"status":"new","surface":"widget"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"conversation.handoff_created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"assigned_to":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The team member following up."},"conversation":{"$ref":"#/components/schemas/WebhookConversationRef","description":"The conversation it came from. Its text is never sent."},"conversation_shared":{"description":"True when the visitor agreed to share the conversation with the team.","type":"boolean"},"created_at":{"description":"When it was raised.","format":"date-time","type":"string"},"id":{"description":"The handoff id.","type":"string"},"kind":{"description":"Who was asked for.","enum":["pastor","crisis_contact"],"type":"string"},"object":{"description":"Always handoff.","enum":["handoff"],"type":"string"},"reachable_by":{"description":"How the visitor can be reached, without the details.","items":{"description":"A contact method.","enum":["email","phone"],"type":"string"},"type":"array"},"status":{"description":"Where follow-up stands.","enum":["new","assigned","replied","resolved","closed"],"type":"string"},"surface":{"description":"Where it was raised.","enum":["staff","widget","share"],"type":"string"}},"required":["id","object","conversation","kind","surface","status","assigned_to","reachable_by","conversation_shared","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"conversation.handoff_created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"conversation.handoff_created","tags":["Webhook events"],"x-group":"Ask"}},"live.ended":{"post":{"description":"A live stream ended, whether finished, stopped, idle, revoked or failed. status and end_reason say which.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `live.ended`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_live_ended","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A live.ended event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"audio_ms":2412000,"billed_ms":2412000,"created_at":"2026-10-13T09:12:10Z","end_reason":"finalized","id":"live_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","last_seq":1873,"object":"live_stream","public_captions":true,"source":"main","status":"ended","status_transitions":{"deleted_at":"2026-10-13T09:12:10Z","disconnected_at":"2026-10-13T08:41:00Z","ended_at":"2026-10-13T09:12:10Z","started_at":"2026-10-13T08:30:00Z"},"teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"}},"previous_attributes":{"status":"created"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"live.ended"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"audio_ms":{"description":"Milliseconds of audio received.","type":"integer"},"billed_ms":{"description":"Milliseconds billed against the plan.","type":"integer"},"created_at":{"description":"When the stream was created.","format":"date-time","type":"string"},"end_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why it ended: finalized, idle, stopped, revoked or failed; null while running."},"id":{"description":"The live stream id.","type":"string"},"language":{"description":"The spoken language.","type":"string"},"last_seq":{"description":"The last caption sequence number.","type":"integer"},"object":{"description":"Always live_stream.","enum":["live_stream"],"type":"string"},"public_captions":{"description":"True when captions are public.","type":"boolean"},"source":{"description":"The stream source name.","type":"string"},"status":{"description":"Where the stream stands.","enum":["created","live","reconnecting","ended","failed"],"type":"string"},"status_transitions":{"additionalProperties":false,"description":"When the stream reached each state.","properties":{"deleted_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was deleted."},"disconnected_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the feed last dropped."},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended."},"started_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it began."}},"required":["started_at","disconnected_at","ended_at","deleted_at"],"type":"object"},"teaching":{"anyOf":[{"$ref":"#/components/schemas/WebhookTeachingRef"},{"type":"null"}],"description":"The teaching created from the service, null until it exists."}},"required":["id","object","source","status","language","public_captions","end_reason","audio_ms","billed_ms","last_seq","teaching","status_transitions","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"live.ended"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"live.ended","tags":["Webhook events"],"x-group":"Live"}},"live.reconnecting":{"post":{"description":"The feed dropped and the stream is waiting for the encoder to return.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `live.reconnecting`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_live_reconnecting","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A live.reconnecting event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"audio_ms":2412000,"billed_ms":2412000,"created_at":"2026-10-13T09:12:10Z","end_reason":"finalized","id":"live_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","last_seq":1873,"object":"live_stream","public_captions":true,"source":"main","status":"ended","status_transitions":{"deleted_at":"2026-10-13T09:12:10Z","disconnected_at":"2026-10-13T08:41:00Z","ended_at":"2026-10-13T09:12:10Z","started_at":"2026-10-13T08:30:00Z"},"teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"}},"previous_attributes":{"status":"created"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"live.reconnecting"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"audio_ms":{"description":"Milliseconds of audio received.","type":"integer"},"billed_ms":{"description":"Milliseconds billed against the plan.","type":"integer"},"created_at":{"description":"When the stream was created.","format":"date-time","type":"string"},"end_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why it ended: finalized, idle, stopped, revoked or failed; null while running."},"id":{"description":"The live stream id.","type":"string"},"language":{"description":"The spoken language.","type":"string"},"last_seq":{"description":"The last caption sequence number.","type":"integer"},"object":{"description":"Always live_stream.","enum":["live_stream"],"type":"string"},"public_captions":{"description":"True when captions are public.","type":"boolean"},"source":{"description":"The stream source name.","type":"string"},"status":{"description":"Where the stream stands.","enum":["created","live","reconnecting","ended","failed"],"type":"string"},"status_transitions":{"additionalProperties":false,"description":"When the stream reached each state.","properties":{"deleted_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was deleted."},"disconnected_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the feed last dropped."},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended."},"started_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it began."}},"required":["started_at","disconnected_at","ended_at","deleted_at"],"type":"object"},"teaching":{"anyOf":[{"$ref":"#/components/schemas/WebhookTeachingRef"},{"type":"null"}],"description":"The teaching created from the service, null until it exists."}},"required":["id","object","source","status","language","public_captions","end_reason","audio_ms","billed_ms","last_seq","teaching","status_transitions","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"live.reconnecting"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"live.reconnecting","tags":["Webhook events"],"x-group":"Live"}},"live.started":{"post":{"description":"A live stream began.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `live.started`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_live_started","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A live.started event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"audio_ms":2412000,"billed_ms":2412000,"created_at":"2026-10-13T09:12:10Z","end_reason":"finalized","id":"live_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","last_seq":1873,"object":"live_stream","public_captions":true,"source":"main","status":"ended","status_transitions":{"deleted_at":"2026-10-13T09:12:10Z","disconnected_at":"2026-10-13T08:41:00Z","ended_at":"2026-10-13T09:12:10Z","started_at":"2026-10-13T08:30:00Z"},"teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"}},"previous_attributes":{"status":"created"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"live.started"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"audio_ms":{"description":"Milliseconds of audio received.","type":"integer"},"billed_ms":{"description":"Milliseconds billed against the plan.","type":"integer"},"created_at":{"description":"When the stream was created.","format":"date-time","type":"string"},"end_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why it ended: finalized, idle, stopped, revoked or failed; null while running."},"id":{"description":"The live stream id.","type":"string"},"language":{"description":"The spoken language.","type":"string"},"last_seq":{"description":"The last caption sequence number.","type":"integer"},"object":{"description":"Always live_stream.","enum":["live_stream"],"type":"string"},"public_captions":{"description":"True when captions are public.","type":"boolean"},"source":{"description":"The stream source name.","type":"string"},"status":{"description":"Where the stream stands.","enum":["created","live","reconnecting","ended","failed"],"type":"string"},"status_transitions":{"additionalProperties":false,"description":"When the stream reached each state.","properties":{"deleted_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was deleted."},"disconnected_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the feed last dropped."},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended."},"started_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it began."}},"required":["started_at","disconnected_at","ended_at","deleted_at"],"type":"object"},"teaching":{"anyOf":[{"$ref":"#/components/schemas/WebhookTeachingRef"},{"type":"null"}],"description":"The teaching created from the service, null until it exists."}},"required":["id","object","source","status","language","public_captions","end_reason","audio_ms","billed_ms","last_seq","teaching","status_transitions","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"live.started"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"live.started","tags":["Webhook events"],"x-group":"Live"}},"live.stream.deleted":{"post":{"description":"A finished live stream was deleted, with its captions, recordings and timeline. The teaching made from it is kept.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `live.stream.deleted`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_live_stream_deleted","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A live.stream.deleted event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"audio_ms":2412000,"billed_ms":2412000,"created_at":"2026-10-13T09:12:10Z","end_reason":"finalized","id":"live_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","last_seq":1873,"object":"live_stream","public_captions":true,"source":"main","status":"ended","status_transitions":{"deleted_at":"2026-10-13T09:12:10Z","disconnected_at":"2026-10-13T08:41:00Z","ended_at":"2026-10-13T09:12:10Z","started_at":"2026-10-13T08:30:00Z"},"teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"live.stream.deleted"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"audio_ms":{"description":"Milliseconds of audio received.","type":"integer"},"billed_ms":{"description":"Milliseconds billed against the plan.","type":"integer"},"created_at":{"description":"When the stream was created.","format":"date-time","type":"string"},"end_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why it ended: finalized, idle, stopped, revoked or failed; null while running."},"id":{"description":"The live stream id.","type":"string"},"language":{"description":"The spoken language.","type":"string"},"last_seq":{"description":"The last caption sequence number.","type":"integer"},"object":{"description":"Always live_stream.","enum":["live_stream"],"type":"string"},"public_captions":{"description":"True when captions are public.","type":"boolean"},"source":{"description":"The stream source name.","type":"string"},"status":{"description":"Where the stream stands.","enum":["created","live","reconnecting","ended","failed"],"type":"string"},"status_transitions":{"additionalProperties":false,"description":"When the stream reached each state.","properties":{"deleted_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was deleted."},"disconnected_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the feed last dropped."},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended."},"started_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it began."}},"required":["started_at","disconnected_at","ended_at","deleted_at"],"type":"object"},"teaching":{"anyOf":[{"$ref":"#/components/schemas/WebhookTeachingRef"},{"type":"null"}],"description":"The teaching created from the service, null until it exists."}},"required":["id","object","source","status","language","public_captions","end_reason","audio_ms","billed_ms","last_seq","teaching","status_transitions","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"live.stream.deleted"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"live.stream.deleted","tags":["Webhook events"],"x-group":"Live"}},"live.teaching_created":{"post":{"description":"A finished live service became a teaching with its captions as the transcript. teaching points to it.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `live.teaching_created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_live_teaching_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A live.teaching_created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"audio_ms":2412000,"billed_ms":2412000,"created_at":"2026-10-13T09:12:10Z","end_reason":"finalized","id":"live_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","last_seq":1873,"object":"live_stream","public_captions":true,"source":"main","status":"ended","status_transitions":{"deleted_at":"2026-10-13T09:12:10Z","disconnected_at":"2026-10-13T08:41:00Z","ended_at":"2026-10-13T09:12:10Z","started_at":"2026-10-13T08:30:00Z"},"teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"live.teaching_created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"audio_ms":{"description":"Milliseconds of audio received.","type":"integer"},"billed_ms":{"description":"Milliseconds billed against the plan.","type":"integer"},"created_at":{"description":"When the stream was created.","format":"date-time","type":"string"},"end_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why it ended: finalized, idle, stopped, revoked or failed; null while running."},"id":{"description":"The live stream id.","type":"string"},"language":{"description":"The spoken language.","type":"string"},"last_seq":{"description":"The last caption sequence number.","type":"integer"},"object":{"description":"Always live_stream.","enum":["live_stream"],"type":"string"},"public_captions":{"description":"True when captions are public.","type":"boolean"},"source":{"description":"The stream source name.","type":"string"},"status":{"description":"Where the stream stands.","enum":["created","live","reconnecting","ended","failed"],"type":"string"},"status_transitions":{"additionalProperties":false,"description":"When the stream reached each state.","properties":{"deleted_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was deleted."},"disconnected_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the feed last dropped."},"ended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it ended."},"started_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it began."}},"required":["started_at","disconnected_at","ended_at","deleted_at"],"type":"object"},"teaching":{"anyOf":[{"$ref":"#/components/schemas/WebhookTeachingRef"},{"type":"null"}],"description":"The teaching created from the service, null until it exists."}},"required":["id","object","source","status","language","public_captions","end_reason","audio_ms","billed_ms","last_seq","teaching","status_transitions","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"live.teaching_created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"live.teaching_created","tags":["Webhook events"],"x-group":"Live"}},"member.invited":{"post":{"description":"Someone was invited to the team. The address is not included.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `member.invited`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_member_invited","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A member.invited event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","expires_at":"2026-10-13T09:12:10Z","id":"invt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","invited_by":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"object":"invitation","role":"editor","status":"pending"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"member.invited"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When it was sent.","format":"date-time","type":"string"},"expires_at":{"description":"When it stops working.","format":"date-time","type":"string"},"id":{"description":"The invitation id.","type":"string"},"invited_by":{"$ref":"#/components/schemas/WebhookUserIdRef","description":"The team member who sent it."},"object":{"description":"Always invitation.","enum":["invitation"],"type":"string"},"role":{"description":"The role offered.","type":"string"},"status":{"description":"Where the invitation stands.","enum":["pending","accepted","expired"],"type":"string"}},"required":["id","object","role","status","invited_by","created_at","expires_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"member.invited"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"member.invited","tags":["Webhook events"],"x-group":"Members and team"}},"member.joined":{"post":{"description":"Someone joined the team by accepting an invitation or through single sign-on provisioning.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `member.joined`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_member_joined","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A member.joined event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","invitation":{"id":"invt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"invitation"},"joined_at":"2026-10-13T09:12:10Z","object":"member","removed_at":"2026-10-13T09:12:10Z","role":"editor","via":"invitation"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"member.joined"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"id":{"description":"The member id.","type":"string"},"invitation":{"additionalProperties":false,"description":"The invitation they accepted.","properties":{"id":{"description":"The invitation id.","type":"string"},"object":{"description":"Always invitation.","enum":["invitation"],"type":"string"}},"required":["id","object"],"type":"object"},"joined_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they joined, null when unknown."},"object":{"description":"Always member.","enum":["member"],"type":"string"},"removed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they were removed, null while a member."},"role":{"description":"Their role in the church.","type":"string"},"via":{"description":"How they joined, on join events.","enum":["invitation","scim"],"type":"string"}},"required":["id","object","role","joined_at","removed_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"member.joined"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"member.joined","tags":["Webhook events"],"x-group":"Members and team"}},"member.removed":{"post":{"description":"A member was removed from the team. The object holds the role they had.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `member.removed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_member_removed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A member.removed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","invitation":{"id":"invt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"invitation"},"joined_at":"2026-10-13T09:12:10Z","object":"member","removed_at":"2026-10-13T09:12:10Z","role":"editor","via":"invitation"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"member.removed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"id":{"description":"The member id.","type":"string"},"invitation":{"additionalProperties":false,"description":"The invitation they accepted.","properties":{"id":{"description":"The invitation id.","type":"string"},"object":{"description":"Always invitation.","enum":["invitation"],"type":"string"}},"required":["id","object"],"type":"object"},"joined_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they joined, null when unknown."},"object":{"description":"Always member.","enum":["member"],"type":"string"},"removed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they were removed, null while a member."},"role":{"description":"Their role in the church.","type":"string"},"via":{"description":"How they joined, on join events.","enum":["invitation","scim"],"type":"string"}},"required":["id","object","role","joined_at","removed_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"member.removed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"member.removed","tags":["Webhook events"],"x-group":"Members and team"}},"member.role_changed":{"post":{"description":"A member's role changed. previous_attributes.role is the role they had.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `member.role_changed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_member_role_changed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A member.role_changed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","invitation":{"id":"invt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"invitation"},"joined_at":"2026-10-13T09:12:10Z","object":"member","removed_at":"2026-10-13T09:12:10Z","role":"editor","via":"invitation"},"previous_attributes":{"role":"Previous editor"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"member.role_changed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"id":{"description":"The member id.","type":"string"},"invitation":{"additionalProperties":false,"description":"The invitation they accepted.","properties":{"id":{"description":"The invitation id.","type":"string"},"object":{"description":"Always invitation.","enum":["invitation"],"type":"string"}},"required":["id","object"],"type":"object"},"joined_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they joined, null when unknown."},"object":{"description":"Always member.","enum":["member"],"type":"string"},"removed_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When they were removed, null while a member."},"role":{"description":"Their role in the church.","type":"string"},"via":{"description":"How they joined, on join events.","enum":["invitation","scim"],"type":"string"}},"required":["id","object","role","joined_at","removed_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: role.","type":"object"}},"type":"object"},"type":{"const":"member.role_changed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"member.role_changed","tags":["Webhook events"],"x-group":"Members and team"}},"note.approved":{"post":{"description":"A note was approved, by a person or automatically. approval_kind says which.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `note.approved`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_note_approved","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A note.approved event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"approval_kind":"human","approved_at":"2026-10-13T09:00:00Z","church":"Grace Place","created_at":"2026-10-13T09:12:10Z","failure_reason":"","id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","model_id":"gemini-2.5-pro","needs_person_reason":"","object":"note","prompt_version":"notes.v14","published_at":"2026-10-13T09:12:10Z","returned_reason":"","row_version":5,"sections":[{"body":"Paul reminds us that nothing in our hardest seasons is wasted.","h":"Called by purpose"}],"share_path":"/s/romans-8-nothing-can-separate-us","share_slug":"romans-8-nothing-can-separate-us","speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"published","summary":"God works all things together for good for those who love him.","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"updated_at":"2026-10-13T09:12:10Z","version":3,"warnings":[]},"previous_attributes":{"status":"draft"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"note.approved"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"approval_kind":{"anyOf":[{"enum":["human","automatic"],"type":"string"},{"type":"null"}],"description":"How it was approved: human or automatic; null before approval."},"approved_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was approved."},"church":{"description":"The church name printed on the note.","type":"string"},"created_at":{"description":"When the first draft was written.","format":"date-time","type":"string"},"failure_reason":{"description":"A short plain reason when generation failed.","type":"string"},"id":{"description":"The note id.","type":"string"},"model_id":{"description":"The model that wrote it.","type":"string"},"needs_person_reason":{"description":"Why automatic approval stopped for a person, empty otherwise.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"published_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was published."},"returned_reason":{"description":"What a reviewer asked to change, empty when nothing was returned.","type":"string"},"row_version":{"description":"Bumps on every change; use it for If-Match.","type":"integer"},"sections":{"description":"The note body in order.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text in markdown.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"required":["h","body"],"type":"object"},"type":"array"},"share_path":{"description":"The share page path, empty until published.","type":"string"},"share_slug":{"description":"The share page slug, empty until published.","type":"string"},"speaker":{"description":"The speaker printed on the note.","type":"string"},"speaker_evidence":{"description":"Why that speaker was guessed.","type":"string"},"speaker_inferred":{"description":"True when the speaker was guessed.","type":"boolean"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"},"summary":{"description":"The short summary.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note summarises."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"version":{"description":"The saved version number.","type":"integer"},"warnings":{"description":"Things the team should check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","teaching","status","summary","sections","version","row_version","approval_kind","approved_at","published_at","returned_reason","needs_person_reason","failure_reason","warnings","share_slug","share_path","church","speaker","speaker_inferred","speaker_evidence","prompt_version","model_id","created_at","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"note.approved"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"note.approved","tags":["Webhook events"],"x-group":"Notes"}},"note.draft_created":{"post":{"description":"A draft note was generated from a transcript.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `note.draft_created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_note_draft_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A note.draft_created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"approval_kind":"human","approved_at":"2026-10-13T09:00:00Z","church":"Grace Place","created_at":"2026-10-13T09:12:10Z","failure_reason":"","id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","model_id":"gemini-2.5-pro","needs_person_reason":"","object":"note","prompt_version":"notes.v14","published_at":"2026-10-13T09:12:10Z","returned_reason":"","row_version":5,"sections":[{"body":"Paul reminds us that nothing in our hardest seasons is wasted.","h":"Called by purpose"}],"share_path":"/s/romans-8-nothing-can-separate-us","share_slug":"romans-8-nothing-can-separate-us","speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"published","summary":"God works all things together for good for those who love him.","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"updated_at":"2026-10-13T09:12:10Z","version":3,"warnings":[]}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"note.draft_created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"approval_kind":{"anyOf":[{"enum":["human","automatic"],"type":"string"},{"type":"null"}],"description":"How it was approved: human or automatic; null before approval."},"approved_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was approved."},"church":{"description":"The church name printed on the note.","type":"string"},"created_at":{"description":"When the first draft was written.","format":"date-time","type":"string"},"failure_reason":{"description":"A short plain reason when generation failed.","type":"string"},"id":{"description":"The note id.","type":"string"},"model_id":{"description":"The model that wrote it.","type":"string"},"needs_person_reason":{"description":"Why automatic approval stopped for a person, empty otherwise.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"published_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was published."},"returned_reason":{"description":"What a reviewer asked to change, empty when nothing was returned.","type":"string"},"row_version":{"description":"Bumps on every change; use it for If-Match.","type":"integer"},"sections":{"description":"The note body in order.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text in markdown.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"required":["h","body"],"type":"object"},"type":"array"},"share_path":{"description":"The share page path, empty until published.","type":"string"},"share_slug":{"description":"The share page slug, empty until published.","type":"string"},"speaker":{"description":"The speaker printed on the note.","type":"string"},"speaker_evidence":{"description":"Why that speaker was guessed.","type":"string"},"speaker_inferred":{"description":"True when the speaker was guessed.","type":"boolean"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"},"summary":{"description":"The short summary.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note summarises."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"version":{"description":"The saved version number.","type":"integer"},"warnings":{"description":"Things the team should check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","teaching","status","summary","sections","version","row_version","approval_kind","approved_at","published_at","returned_reason","needs_person_reason","failure_reason","warnings","share_slug","share_path","church","speaker","speaker_inferred","speaker_evidence","prompt_version","model_id","created_at","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"note.draft_created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"note.draft_created","tags":["Webhook events"],"x-group":"Notes"}},"note.published":{"post":{"description":"A note was published to its share page.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `note.published`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_note_published","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A note.published event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"approval_kind":"human","approved_at":"2026-10-13T09:00:00Z","church":"Grace Place","created_at":"2026-10-13T09:12:10Z","failure_reason":"","id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","model_id":"gemini-2.5-pro","needs_person_reason":"","object":"note","prompt_version":"notes.v14","published_at":"2026-10-13T09:12:10Z","returned_reason":"","row_version":5,"sections":[{"body":"Paul reminds us that nothing in our hardest seasons is wasted.","h":"Called by purpose"}],"share_path":"/s/romans-8-nothing-can-separate-us","share_slug":"romans-8-nothing-can-separate-us","speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"published","summary":"God works all things together for good for those who love him.","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"updated_at":"2026-10-13T09:12:10Z","version":3,"warnings":[]},"previous_attributes":{"status":"draft"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"note.published"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"approval_kind":{"anyOf":[{"enum":["human","automatic"],"type":"string"},{"type":"null"}],"description":"How it was approved: human or automatic; null before approval."},"approved_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was approved."},"church":{"description":"The church name printed on the note.","type":"string"},"created_at":{"description":"When the first draft was written.","format":"date-time","type":"string"},"failure_reason":{"description":"A short plain reason when generation failed.","type":"string"},"id":{"description":"The note id.","type":"string"},"model_id":{"description":"The model that wrote it.","type":"string"},"needs_person_reason":{"description":"Why automatic approval stopped for a person, empty otherwise.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"published_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was published."},"returned_reason":{"description":"What a reviewer asked to change, empty when nothing was returned.","type":"string"},"row_version":{"description":"Bumps on every change; use it for If-Match.","type":"integer"},"sections":{"description":"The note body in order.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text in markdown.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"required":["h","body"],"type":"object"},"type":"array"},"share_path":{"description":"The share page path, empty until published.","type":"string"},"share_slug":{"description":"The share page slug, empty until published.","type":"string"},"speaker":{"description":"The speaker printed on the note.","type":"string"},"speaker_evidence":{"description":"Why that speaker was guessed.","type":"string"},"speaker_inferred":{"description":"True when the speaker was guessed.","type":"boolean"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"},"summary":{"description":"The short summary.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note summarises."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"version":{"description":"The saved version number.","type":"integer"},"warnings":{"description":"Things the team should check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","teaching","status","summary","sections","version","row_version","approval_kind","approved_at","published_at","returned_reason","needs_person_reason","failure_reason","warnings","share_slug","share_path","church","speaker","speaker_inferred","speaker_evidence","prompt_version","model_id","created_at","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"note.published"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"note.published","tags":["Webhook events"],"x-group":"Notes"}},"note.returned":{"post":{"description":"A reviewer sent a note back to its author with a reason. returned_reason carries it.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `note.returned`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_note_returned","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A note.returned event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"approval_kind":"human","approved_at":"2026-10-13T09:00:00Z","church":"Grace Place","created_at":"2026-10-13T09:12:10Z","failure_reason":"","id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","model_id":"gemini-2.5-pro","needs_person_reason":"","object":"note","prompt_version":"notes.v14","published_at":"2026-10-13T09:12:10Z","returned_reason":"","row_version":5,"sections":[{"body":"Paul reminds us that nothing in our hardest seasons is wasted.","h":"Called by purpose"}],"share_path":"/s/romans-8-nothing-can-separate-us","share_slug":"romans-8-nothing-can-separate-us","speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"published","summary":"God works all things together for good for those who love him.","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"updated_at":"2026-10-13T09:12:10Z","version":3,"warnings":[]},"previous_attributes":{"status":"draft"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"note.returned"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"approval_kind":{"anyOf":[{"enum":["human","automatic"],"type":"string"},{"type":"null"}],"description":"How it was approved: human or automatic; null before approval."},"approved_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was approved."},"church":{"description":"The church name printed on the note.","type":"string"},"created_at":{"description":"When the first draft was written.","format":"date-time","type":"string"},"failure_reason":{"description":"A short plain reason when generation failed.","type":"string"},"id":{"description":"The note id.","type":"string"},"model_id":{"description":"The model that wrote it.","type":"string"},"needs_person_reason":{"description":"Why automatic approval stopped for a person, empty otherwise.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"published_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was published."},"returned_reason":{"description":"What a reviewer asked to change, empty when nothing was returned.","type":"string"},"row_version":{"description":"Bumps on every change; use it for If-Match.","type":"integer"},"sections":{"description":"The note body in order.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text in markdown.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"required":["h","body"],"type":"object"},"type":"array"},"share_path":{"description":"The share page path, empty until published.","type":"string"},"share_slug":{"description":"The share page slug, empty until published.","type":"string"},"speaker":{"description":"The speaker printed on the note.","type":"string"},"speaker_evidence":{"description":"Why that speaker was guessed.","type":"string"},"speaker_inferred":{"description":"True when the speaker was guessed.","type":"boolean"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"},"summary":{"description":"The short summary.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note summarises."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"version":{"description":"The saved version number.","type":"integer"},"warnings":{"description":"Things the team should check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","teaching","status","summary","sections","version","row_version","approval_kind","approved_at","published_at","returned_reason","needs_person_reason","failure_reason","warnings","share_slug","share_path","church","speaker","speaker_inferred","speaker_evidence","prompt_version","model_id","created_at","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"note.returned"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"note.returned","tags":["Webhook events"],"x-group":"Notes"}},"note.review_requested":{"post":{"description":"A note was sent for review.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `note.review_requested`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_note_review_requested","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A note.review_requested event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"approval_kind":"human","approved_at":"2026-10-13T09:00:00Z","church":"Grace Place","created_at":"2026-10-13T09:12:10Z","failure_reason":"","id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","model_id":"gemini-2.5-pro","needs_person_reason":"","object":"note","prompt_version":"notes.v14","published_at":"2026-10-13T09:12:10Z","returned_reason":"","row_version":5,"sections":[{"body":"Paul reminds us that nothing in our hardest seasons is wasted.","h":"Called by purpose"}],"share_path":"/s/romans-8-nothing-can-separate-us","share_slug":"romans-8-nothing-can-separate-us","speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"published","summary":"God works all things together for good for those who love him.","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"updated_at":"2026-10-13T09:12:10Z","version":3,"warnings":[]},"previous_attributes":{"status":"draft"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"note.review_requested"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"approval_kind":{"anyOf":[{"enum":["human","automatic"],"type":"string"},{"type":"null"}],"description":"How it was approved: human or automatic; null before approval."},"approved_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was approved."},"church":{"description":"The church name printed on the note.","type":"string"},"created_at":{"description":"When the first draft was written.","format":"date-time","type":"string"},"failure_reason":{"description":"A short plain reason when generation failed.","type":"string"},"id":{"description":"The note id.","type":"string"},"model_id":{"description":"The model that wrote it.","type":"string"},"needs_person_reason":{"description":"Why automatic approval stopped for a person, empty otherwise.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"published_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was published."},"returned_reason":{"description":"What a reviewer asked to change, empty when nothing was returned.","type":"string"},"row_version":{"description":"Bumps on every change; use it for If-Match.","type":"integer"},"sections":{"description":"The note body in order.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text in markdown.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"required":["h","body"],"type":"object"},"type":"array"},"share_path":{"description":"The share page path, empty until published.","type":"string"},"share_slug":{"description":"The share page slug, empty until published.","type":"string"},"speaker":{"description":"The speaker printed on the note.","type":"string"},"speaker_evidence":{"description":"Why that speaker was guessed.","type":"string"},"speaker_inferred":{"description":"True when the speaker was guessed.","type":"boolean"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"},"summary":{"description":"The short summary.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note summarises."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"version":{"description":"The saved version number.","type":"integer"},"warnings":{"description":"Things the team should check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","teaching","status","summary","sections","version","row_version","approval_kind","approved_at","published_at","returned_reason","needs_person_reason","failure_reason","warnings","share_slug","share_path","church","speaker","speaker_inferred","speaker_evidence","prompt_version","model_id","created_at","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"note.review_requested"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"note.review_requested","tags":["Webhook events"],"x-group":"Notes"}},"note.superseded":{"post":{"description":"A note was replaced and its share page was unpublished.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `note.superseded`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_note_superseded","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A note.superseded event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"approval_kind":"human","approved_at":"2026-10-13T09:00:00Z","church":"Grace Place","created_at":"2026-10-13T09:12:10Z","failure_reason":"","id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","model_id":"gemini-2.5-pro","needs_person_reason":"","object":"note","prompt_version":"notes.v14","published_at":"2026-10-13T09:12:10Z","returned_reason":"","row_version":5,"sections":[{"body":"Paul reminds us that nothing in our hardest seasons is wasted.","h":"Called by purpose"}],"share_path":"/s/romans-8-nothing-can-separate-us","share_slug":"romans-8-nothing-can-separate-us","speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"published","summary":"God works all things together for good for those who love him.","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"updated_at":"2026-10-13T09:12:10Z","version":3,"warnings":[]},"previous_attributes":{"status":"draft"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"note.superseded"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"approval_kind":{"anyOf":[{"enum":["human","automatic"],"type":"string"},{"type":"null"}],"description":"How it was approved: human or automatic; null before approval."},"approved_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was approved."},"church":{"description":"The church name printed on the note.","type":"string"},"created_at":{"description":"When the first draft was written.","format":"date-time","type":"string"},"failure_reason":{"description":"A short plain reason when generation failed.","type":"string"},"id":{"description":"The note id.","type":"string"},"model_id":{"description":"The model that wrote it.","type":"string"},"needs_person_reason":{"description":"Why automatic approval stopped for a person, empty otherwise.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"published_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was published."},"returned_reason":{"description":"What a reviewer asked to change, empty when nothing was returned.","type":"string"},"row_version":{"description":"Bumps on every change; use it for If-Match.","type":"integer"},"sections":{"description":"The note body in order.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text in markdown.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"required":["h","body"],"type":"object"},"type":"array"},"share_path":{"description":"The share page path, empty until published.","type":"string"},"share_slug":{"description":"The share page slug, empty until published.","type":"string"},"speaker":{"description":"The speaker printed on the note.","type":"string"},"speaker_evidence":{"description":"Why that speaker was guessed.","type":"string"},"speaker_inferred":{"description":"True when the speaker was guessed.","type":"boolean"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"},"summary":{"description":"The short summary.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note summarises."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"version":{"description":"The saved version number.","type":"integer"},"warnings":{"description":"Things the team should check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","teaching","status","summary","sections","version","row_version","approval_kind","approved_at","published_at","returned_reason","needs_person_reason","failure_reason","warnings","share_slug","share_path","church","speaker","speaker_inferred","speaker_evidence","prompt_version","model_id","created_at","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"note.superseded"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"note.superseded","tags":["Webhook events"],"x-group":"Notes"}},"note.updated":{"post":{"description":"A draft or in-review note was edited and a new version was saved.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `note.updated`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_note_updated","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A note.updated event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"approval_kind":"human","approved_at":"2026-10-13T09:00:00Z","church":"Grace Place","created_at":"2026-10-13T09:12:10Z","failure_reason":"","id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","model_id":"gemini-2.5-pro","needs_person_reason":"","object":"note","prompt_version":"notes.v14","published_at":"2026-10-13T09:12:10Z","returned_reason":"","row_version":5,"sections":[{"body":"Paul reminds us that nothing in our hardest seasons is wasted.","h":"Called by purpose"}],"share_path":"/s/romans-8-nothing-can-separate-us","share_slug":"romans-8-nothing-can-separate-us","speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"published","summary":"God works all things together for good for those who love him.","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"updated_at":"2026-10-13T09:12:10Z","version":3,"warnings":[]},"previous_attributes":{"row_version":4,"summary":"Previous God works all things together for good for those who love him.","version":2}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"note.updated"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"approval_kind":{"anyOf":[{"enum":["human","automatic"],"type":"string"},{"type":"null"}],"description":"How it was approved: human or automatic; null before approval."},"approved_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was approved."},"church":{"description":"The church name printed on the note.","type":"string"},"created_at":{"description":"When the first draft was written.","format":"date-time","type":"string"},"failure_reason":{"description":"A short plain reason when generation failed.","type":"string"},"id":{"description":"The note id.","type":"string"},"model_id":{"description":"The model that wrote it.","type":"string"},"needs_person_reason":{"description":"Why automatic approval stopped for a person, empty otherwise.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"published_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was published."},"returned_reason":{"description":"What a reviewer asked to change, empty when nothing was returned.","type":"string"},"row_version":{"description":"Bumps on every change; use it for If-Match.","type":"integer"},"sections":{"description":"The note body in order.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text in markdown.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"required":["h","body"],"type":"object"},"type":"array"},"share_path":{"description":"The share page path, empty until published.","type":"string"},"share_slug":{"description":"The share page slug, empty until published.","type":"string"},"speaker":{"description":"The speaker printed on the note.","type":"string"},"speaker_evidence":{"description":"Why that speaker was guessed.","type":"string"},"speaker_inferred":{"description":"True when the speaker was guessed.","type":"boolean"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"},"summary":{"description":"The short summary.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note summarises."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"version":{"description":"The saved version number.","type":"integer"},"warnings":{"description":"Things the team should check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","teaching","status","summary","sections","version","row_version","approval_kind","approved_at","published_at","returned_reason","needs_person_reason","failure_reason","warnings","share_slug","share_path","church","speaker","speaker_inferred","speaker_evidence","prompt_version","model_id","created_at","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: summary, version, row_version.","type":"object"}},"type":"object"},"type":{"const":"note.updated"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"note.updated","tags":["Webhook events"],"x-group":"Notes"}},"output.created":{"post":{"description":"A devotional, blog post, newsletter or study guide was generated for the first time.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `output.created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_output_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A output.created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"body_md":"The Spirit leads gently, and we follow.","changes_requested":false,"id":"out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"devotional","language":"en","meta":{"subject":"Walk in step with the Spirit"},"model_id":"gemini-2.5-pro","note":{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","status":"approved"},"note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"output","prompt_version":"outputs.v9","review_comment":"","row_version":4,"sections":[{"body":"The Spirit leads gently, and we follow.","heading":"Reflection","key":"reflection"}],"source_note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","source_version":3,"stale":false,"stale_acknowledged":false,"stale_reason":"","status":"published","status_detail":"","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","title":"Walk in step with the Spirit","updated_at":"2026-10-13T09:12:10Z","verses":[{"ref":"Romans 8:14","status":"verified"}],"warnings":[],"word_count":412}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"output.created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"body_md":{"description":"The full text in markdown.","type":"string"},"changes_requested":{"description":"True when a reviewer sent it back.","type":"boolean"},"id":{"description":"The output id.","type":"string"},"kind":{"description":"The kind of output.","enum":["devotional","blog","newsletter","study_guide"],"type":"string"},"language":{"description":"The output language.","type":"string"},"meta":{"additionalProperties":true,"description":"Kind-specific details such as a subject line.","type":"object"},"model_id":{"description":"The model that wrote it.","type":"string"},"note":{"anyOf":[{"$ref":"#/components/schemas/WebhookNoteRef"},{"type":"null"}],"description":"The note it was written from."},"note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note id, null when none."},"object":{"description":"Always output.","enum":["output"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"review_comment":{"description":"What a reviewer asked to change.","type":"string"},"row_version":{"description":"Bumps on every change.","type":"integer"},"sections":{"description":"The text split into its sections.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text.","type":"string"},"heading":{"description":"The section heading.","type":"string"},"key":{"description":"The section key.","type":"string"}},"required":["key","heading","body"],"type":"object"},"type":"array"},"source_note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note version it was written from."},"source_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The note version number it was written from."},"stale":{"description":"True when the source note changed since this was written.","type":"boolean"},"stale_acknowledged":{"description":"True when a reviewer accepted the stale state.","type":"boolean"},"stale_reason":{"description":"source_changed, source_unapproved, source_returned or source_superseded; empty when not stale.","type":"string"},"status":{"description":"The output status.","enum":["queued","failed","draft","in_review","approved","published"],"type":"string"},"status_detail":{"description":"A short plain note about the status.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching it was written from."},"teaching_id":{"description":"The teaching id.","type":"string"},"title":{"description":"The output title.","type":"string"},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"verses":{"description":"The verses it quotes, with whether each was verified against the text.","items":{"additionalProperties":false,"description":"One verse.","properties":{"ref":{"description":"The reference.","type":"string"},"status":{"description":"verified or unverified.","type":"string"}},"required":["ref","status"],"type":"object"},"type":"array"},"warnings":{"description":"Things to check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"},"word_count":{"description":"Words in the body.","type":"integer"}},"required":["id","object","teaching","note","teaching_id","note_id","kind","status","language","title","body_md","meta","sections","verses","warnings","prompt_version","model_id","word_count","row_version","source_note_id","source_version","stale","stale_reason","stale_acknowledged","review_comment","changes_requested","status_detail","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"output.created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"output.created","tags":["Webhook events"],"x-group":"Outputs"}},"output.published":{"post":{"description":"An output moved to published.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `output.published`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_output_published","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A output.published event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"body_md":"The Spirit leads gently, and we follow.","changes_requested":false,"id":"out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"devotional","language":"en","meta":{"subject":"Walk in step with the Spirit"},"model_id":"gemini-2.5-pro","note":{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","status":"approved"},"note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"output","prompt_version":"outputs.v9","review_comment":"","row_version":4,"sections":[{"body":"The Spirit leads gently, and we follow.","heading":"Reflection","key":"reflection"}],"source_note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","source_version":3,"stale":false,"stale_acknowledged":false,"stale_reason":"","status":"published","status_detail":"","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","title":"Walk in step with the Spirit","updated_at":"2026-10-13T09:12:10Z","verses":[{"ref":"Romans 8:14","status":"verified"}],"warnings":[],"word_count":412},"previous_attributes":{"status":"queued"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"output.published"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"body_md":{"description":"The full text in markdown.","type":"string"},"changes_requested":{"description":"True when a reviewer sent it back.","type":"boolean"},"id":{"description":"The output id.","type":"string"},"kind":{"description":"The kind of output.","enum":["devotional","blog","newsletter","study_guide"],"type":"string"},"language":{"description":"The output language.","type":"string"},"meta":{"additionalProperties":true,"description":"Kind-specific details such as a subject line.","type":"object"},"model_id":{"description":"The model that wrote it.","type":"string"},"note":{"anyOf":[{"$ref":"#/components/schemas/WebhookNoteRef"},{"type":"null"}],"description":"The note it was written from."},"note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note id, null when none."},"object":{"description":"Always output.","enum":["output"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"review_comment":{"description":"What a reviewer asked to change.","type":"string"},"row_version":{"description":"Bumps on every change.","type":"integer"},"sections":{"description":"The text split into its sections.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text.","type":"string"},"heading":{"description":"The section heading.","type":"string"},"key":{"description":"The section key.","type":"string"}},"required":["key","heading","body"],"type":"object"},"type":"array"},"source_note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note version it was written from."},"source_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The note version number it was written from."},"stale":{"description":"True when the source note changed since this was written.","type":"boolean"},"stale_acknowledged":{"description":"True when a reviewer accepted the stale state.","type":"boolean"},"stale_reason":{"description":"source_changed, source_unapproved, source_returned or source_superseded; empty when not stale.","type":"string"},"status":{"description":"The output status.","enum":["queued","failed","draft","in_review","approved","published"],"type":"string"},"status_detail":{"description":"A short plain note about the status.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching it was written from."},"teaching_id":{"description":"The teaching id.","type":"string"},"title":{"description":"The output title.","type":"string"},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"verses":{"description":"The verses it quotes, with whether each was verified against the text.","items":{"additionalProperties":false,"description":"One verse.","properties":{"ref":{"description":"The reference.","type":"string"},"status":{"description":"verified or unverified.","type":"string"}},"required":["ref","status"],"type":"object"},"type":"array"},"warnings":{"description":"Things to check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"},"word_count":{"description":"Words in the body.","type":"integer"}},"required":["id","object","teaching","note","teaching_id","note_id","kind","status","language","title","body_md","meta","sections","verses","warnings","prompt_version","model_id","word_count","row_version","source_note_id","source_version","stale","stale_reason","stale_acknowledged","review_comment","changes_requested","status_detail","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"output.published"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"output.published","tags":["Webhook events"],"x-group":"Outputs"}},"output.stale":{"post":{"description":"The note an output was written from changed, was returned or was replaced, so the output may no longer match it. stale_reason says which.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `output.stale`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_output_stale","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A output.stale event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"body_md":"The Spirit leads gently, and we follow.","changes_requested":false,"id":"out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"devotional","language":"en","meta":{"subject":"Walk in step with the Spirit"},"model_id":"gemini-2.5-pro","note":{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","status":"approved"},"note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"output","prompt_version":"outputs.v9","review_comment":"","row_version":4,"sections":[{"body":"The Spirit leads gently, and we follow.","heading":"Reflection","key":"reflection"}],"source_note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","source_version":3,"stale":false,"stale_acknowledged":false,"stale_reason":"","status":"published","status_detail":"","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","title":"Walk in step with the Spirit","updated_at":"2026-10-13T09:12:10Z","verses":[{"ref":"Romans 8:14","status":"verified"}],"warnings":[],"word_count":412},"previous_attributes":{"stale":true,"stale_reason":"Previous "}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"output.stale"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"body_md":{"description":"The full text in markdown.","type":"string"},"changes_requested":{"description":"True when a reviewer sent it back.","type":"boolean"},"id":{"description":"The output id.","type":"string"},"kind":{"description":"The kind of output.","enum":["devotional","blog","newsletter","study_guide"],"type":"string"},"language":{"description":"The output language.","type":"string"},"meta":{"additionalProperties":true,"description":"Kind-specific details such as a subject line.","type":"object"},"model_id":{"description":"The model that wrote it.","type":"string"},"note":{"anyOf":[{"$ref":"#/components/schemas/WebhookNoteRef"},{"type":"null"}],"description":"The note it was written from."},"note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note id, null when none."},"object":{"description":"Always output.","enum":["output"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"review_comment":{"description":"What a reviewer asked to change.","type":"string"},"row_version":{"description":"Bumps on every change.","type":"integer"},"sections":{"description":"The text split into its sections.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text.","type":"string"},"heading":{"description":"The section heading.","type":"string"},"key":{"description":"The section key.","type":"string"}},"required":["key","heading","body"],"type":"object"},"type":"array"},"source_note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note version it was written from."},"source_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The note version number it was written from."},"stale":{"description":"True when the source note changed since this was written.","type":"boolean"},"stale_acknowledged":{"description":"True when a reviewer accepted the stale state.","type":"boolean"},"stale_reason":{"description":"source_changed, source_unapproved, source_returned or source_superseded; empty when not stale.","type":"string"},"status":{"description":"The output status.","enum":["queued","failed","draft","in_review","approved","published"],"type":"string"},"status_detail":{"description":"A short plain note about the status.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching it was written from."},"teaching_id":{"description":"The teaching id.","type":"string"},"title":{"description":"The output title.","type":"string"},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"verses":{"description":"The verses it quotes, with whether each was verified against the text.","items":{"additionalProperties":false,"description":"One verse.","properties":{"ref":{"description":"The reference.","type":"string"},"status":{"description":"verified or unverified.","type":"string"}},"required":["ref","status"],"type":"object"},"type":"array"},"warnings":{"description":"Things to check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"},"word_count":{"description":"Words in the body.","type":"integer"}},"required":["id","object","teaching","note","teaching_id","note_id","kind","status","language","title","body_md","meta","sections","verses","warnings","prompt_version","model_id","word_count","row_version","source_note_id","source_version","stale","stale_reason","stale_acknowledged","review_comment","changes_requested","status_detail","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: stale, stale_reason.","type":"object"}},"type":"object"},"type":{"const":"output.stale"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"output.stale","tags":["Webhook events"],"x-group":"Outputs"}},"output.unpublished":{"post":{"description":"A published output was taken back to review. Remove it from wherever you posted it. stale_reason says why when the source changed.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `output.unpublished`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_output_unpublished","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A output.unpublished event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"body_md":"The Spirit leads gently, and we follow.","changes_requested":false,"id":"out_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"devotional","language":"en","meta":{"subject":"Walk in step with the Spirit"},"model_id":"gemini-2.5-pro","note":{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","status":"approved"},"note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"output","prompt_version":"outputs.v9","review_comment":"","row_version":4,"sections":[{"body":"The Spirit leads gently, and we follow.","heading":"Reflection","key":"reflection"}],"source_note_id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","source_version":3,"stale":false,"stale_acknowledged":false,"stale_reason":"","status":"published","status_detail":"","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"teaching_id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","title":"Walk in step with the Spirit","updated_at":"2026-10-13T09:12:10Z","verses":[{"ref":"Romans 8:14","status":"verified"}],"warnings":[],"word_count":412},"previous_attributes":{"stale":true,"status":"queued"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"output.unpublished"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"body_md":{"description":"The full text in markdown.","type":"string"},"changes_requested":{"description":"True when a reviewer sent it back.","type":"boolean"},"id":{"description":"The output id.","type":"string"},"kind":{"description":"The kind of output.","enum":["devotional","blog","newsletter","study_guide"],"type":"string"},"language":{"description":"The output language.","type":"string"},"meta":{"additionalProperties":true,"description":"Kind-specific details such as a subject line.","type":"object"},"model_id":{"description":"The model that wrote it.","type":"string"},"note":{"anyOf":[{"$ref":"#/components/schemas/WebhookNoteRef"},{"type":"null"}],"description":"The note it was written from."},"note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note id, null when none."},"object":{"description":"Always output.","enum":["output"],"type":"string"},"prompt_version":{"description":"The prompt version that wrote it.","type":"string"},"review_comment":{"description":"What a reviewer asked to change.","type":"string"},"row_version":{"description":"Bumps on every change.","type":"integer"},"sections":{"description":"The text split into its sections.","items":{"additionalProperties":false,"description":"One section.","properties":{"body":{"description":"The section text.","type":"string"},"heading":{"description":"The section heading.","type":"string"},"key":{"description":"The section key.","type":"string"}},"required":["key","heading","body"],"type":"object"},"type":"array"},"source_note_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The note version it was written from."},"source_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The note version number it was written from."},"stale":{"description":"True when the source note changed since this was written.","type":"boolean"},"stale_acknowledged":{"description":"True when a reviewer accepted the stale state.","type":"boolean"},"stale_reason":{"description":"source_changed, source_unapproved, source_returned or source_superseded; empty when not stale.","type":"string"},"status":{"description":"The output status.","enum":["queued","failed","draft","in_review","approved","published"],"type":"string"},"status_detail":{"description":"A short plain note about the status.","type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching it was written from."},"teaching_id":{"description":"The teaching id.","type":"string"},"title":{"description":"The output title.","type":"string"},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"verses":{"description":"The verses it quotes, with whether each was verified against the text.","items":{"additionalProperties":false,"description":"One verse.","properties":{"ref":{"description":"The reference.","type":"string"},"status":{"description":"verified or unverified.","type":"string"}},"required":["ref","status"],"type":"object"},"type":"array"},"warnings":{"description":"Things to check before publishing.","items":{"description":"One value.","type":"string"},"type":"array"},"word_count":{"description":"Words in the body.","type":"integer"}},"required":["id","object","teaching","note","teaching_id","note_id","kind","status","language","title","body_md","meta","sections","verses","warnings","prompt_version","model_id","word_count","row_version","source_note_id","source_version","stale","stale_reason","stale_acknowledged","review_comment","changes_requested","status_detail","updated_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status, stale.","type":"object"}},"type":"object"},"type":{"const":"output.unpublished"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"output.unpublished","tags":["Webhook events"],"x-group":"Outputs"}},"partner.church.created":{"post":{"description":"A partner created a customer church through the API.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `partner.church.created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_partner_church_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A partner.church.created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"country":"GB","counts":{"members":6,"published_notes":96,"teachings":148},"created_at":"2026-10-13T09:12:10Z","deletion":{"purge_after":"2026-11-13T09:12:10Z","requested_at":"2026-10-13T09:12:10Z","stage":"scheduled"},"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"sandbox":false,"slug":"grace-place","status":"active","subscription_status":"active","suspended_at":"2026-10-13T09:12:10Z"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"partner.church.created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"country":{"description":"The ISO country code, empty when not set.","type":"string"},"counts":{"additionalProperties":false,"description":"How much the church holds.","properties":{"members":{"description":"Team members.","type":"integer"},"published_notes":{"description":"Published notes.","type":"integer"},"teachings":{"description":"Teachings in the library.","type":"integer"}},"required":["members","teachings","published_notes"],"type":"object"},"created_at":{"description":"When the church was created.","format":"date-time","type":"string"},"deletion":{"anyOf":[{"additionalProperties":false,"properties":{"purge_after":{"description":"When the data is removed.","format":"date-time","type":"string"},"requested_at":{"description":"When deletion was requested.","format":"date-time","type":"string"},"stage":{"description":"scheduled or purged.","enum":["scheduled","purged"],"type":"string"}},"required":["requested_at","purge_after","stage"],"type":"object"},{"type":"null"}],"description":"Set once deletion is scheduled."},"id":{"description":"The church id.","type":"string"},"name":{"description":"The church name.","type":"string"},"object":{"description":"Always church.","enum":["church"],"type":"string"},"plan":{"anyOf":[{"$ref":"#/components/schemas/WebhookPlanRef"},{"type":"null"}],"description":"The plan it is on, null before it has one."},"sandbox":{"description":"True for a free sandbox church that expires.","type":"boolean"},"slug":{"description":"The church web address.","type":"string"},"status":{"description":"Where the church stands.","enum":["active","suspended","deletion_scheduled","deleted"],"type":"string"},"subscription_status":{"description":"The subscription status, empty without a subscription.","type":"string"},"suspended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was suspended."}},"required":["id","object","name","slug","status","sandbox","country","plan","subscription_status","counts","suspended_at","deletion","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"partner.church.created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"partner.church.created","tags":["Webhook events"],"x-group":"Partner"}},"partner.church.deleted":{"post":{"description":"A customer church was scheduled for deletion or removed. deletion.stage is scheduled or purged.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `partner.church.deleted`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_partner_church_deleted","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A partner.church.deleted event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"country":"GB","counts":{"members":6,"published_notes":96,"teachings":148},"created_at":"2026-10-13T09:12:10Z","deletion":{"purge_after":"2026-11-13T09:12:10Z","requested_at":"2026-10-13T09:12:10Z","stage":"scheduled"},"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"sandbox":false,"slug":"grace-place","status":"active","subscription_status":"active","suspended_at":"2026-10-13T09:12:10Z"},"previous_attributes":{"status":"suspended"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"partner.church.deleted"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"country":{"description":"The ISO country code, empty when not set.","type":"string"},"counts":{"additionalProperties":false,"description":"How much the church holds.","properties":{"members":{"description":"Team members.","type":"integer"},"published_notes":{"description":"Published notes.","type":"integer"},"teachings":{"description":"Teachings in the library.","type":"integer"}},"required":["members","teachings","published_notes"],"type":"object"},"created_at":{"description":"When the church was created.","format":"date-time","type":"string"},"deletion":{"anyOf":[{"additionalProperties":false,"properties":{"purge_after":{"description":"When the data is removed.","format":"date-time","type":"string"},"requested_at":{"description":"When deletion was requested.","format":"date-time","type":"string"},"stage":{"description":"scheduled or purged.","enum":["scheduled","purged"],"type":"string"}},"required":["requested_at","purge_after","stage"],"type":"object"},{"type":"null"}],"description":"Set once deletion is scheduled."},"id":{"description":"The church id.","type":"string"},"name":{"description":"The church name.","type":"string"},"object":{"description":"Always church.","enum":["church"],"type":"string"},"plan":{"anyOf":[{"$ref":"#/components/schemas/WebhookPlanRef"},{"type":"null"}],"description":"The plan it is on, null before it has one."},"sandbox":{"description":"True for a free sandbox church that expires.","type":"boolean"},"slug":{"description":"The church web address.","type":"string"},"status":{"description":"Where the church stands.","enum":["active","suspended","deletion_scheduled","deleted"],"type":"string"},"subscription_status":{"description":"The subscription status, empty without a subscription.","type":"string"},"suspended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was suspended."}},"required":["id","object","name","slug","status","sandbox","country","plan","subscription_status","counts","suspended_at","deletion","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"partner.church.deleted"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"partner.church.deleted","tags":["Webhook events"],"x-group":"Partner"}},"partner.church.plan_changed":{"post":{"description":"A customer church moved to a different plan.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `partner.church.plan_changed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_partner_church_plan_changed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A partner.church.plan_changed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"country":"GB","counts":{"members":6,"published_notes":96,"teachings":148},"created_at":"2026-10-13T09:12:10Z","deletion":{"purge_after":"2026-11-13T09:12:10Z","requested_at":"2026-10-13T09:12:10Z","stage":"scheduled"},"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"sandbox":false,"slug":"grace-place","status":"active","subscription_status":"active","suspended_at":"2026-10-13T09:12:10Z"},"previous_attributes":{"plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"partner.church.plan_changed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"country":{"description":"The ISO country code, empty when not set.","type":"string"},"counts":{"additionalProperties":false,"description":"How much the church holds.","properties":{"members":{"description":"Team members.","type":"integer"},"published_notes":{"description":"Published notes.","type":"integer"},"teachings":{"description":"Teachings in the library.","type":"integer"}},"required":["members","teachings","published_notes"],"type":"object"},"created_at":{"description":"When the church was created.","format":"date-time","type":"string"},"deletion":{"anyOf":[{"additionalProperties":false,"properties":{"purge_after":{"description":"When the data is removed.","format":"date-time","type":"string"},"requested_at":{"description":"When deletion was requested.","format":"date-time","type":"string"},"stage":{"description":"scheduled or purged.","enum":["scheduled","purged"],"type":"string"}},"required":["requested_at","purge_after","stage"],"type":"object"},{"type":"null"}],"description":"Set once deletion is scheduled."},"id":{"description":"The church id.","type":"string"},"name":{"description":"The church name.","type":"string"},"object":{"description":"Always church.","enum":["church"],"type":"string"},"plan":{"anyOf":[{"$ref":"#/components/schemas/WebhookPlanRef"},{"type":"null"}],"description":"The plan it is on, null before it has one."},"sandbox":{"description":"True for a free sandbox church that expires.","type":"boolean"},"slug":{"description":"The church web address.","type":"string"},"status":{"description":"Where the church stands.","enum":["active","suspended","deletion_scheduled","deleted"],"type":"string"},"subscription_status":{"description":"The subscription status, empty without a subscription.","type":"string"},"suspended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was suspended."}},"required":["id","object","name","slug","status","sandbox","country","plan","subscription_status","counts","suspended_at","deletion","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: plan.","type":"object"}},"type":"object"},"type":{"const":"partner.church.plan_changed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"partner.church.plan_changed","tags":["Webhook events"],"x-group":"Partner"}},"partner.church.suspended":{"post":{"description":"A customer church was suspended or reinstated. status says which.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `partner.church.suspended`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_partner_church_suspended","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A partner.church.suspended event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"country":"GB","counts":{"members":6,"published_notes":96,"teachings":148},"created_at":"2026-10-13T09:12:10Z","deletion":{"purge_after":"2026-11-13T09:12:10Z","requested_at":"2026-10-13T09:12:10Z","stage":"scheduled"},"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"sandbox":false,"slug":"grace-place","status":"active","subscription_status":"active","suspended_at":"2026-10-13T09:12:10Z"},"previous_attributes":{"status":"suspended","suspended_at":"2026-10-12T09:12:10Z"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"partner.church.suspended"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"country":{"description":"The ISO country code, empty when not set.","type":"string"},"counts":{"additionalProperties":false,"description":"How much the church holds.","properties":{"members":{"description":"Team members.","type":"integer"},"published_notes":{"description":"Published notes.","type":"integer"},"teachings":{"description":"Teachings in the library.","type":"integer"}},"required":["members","teachings","published_notes"],"type":"object"},"created_at":{"description":"When the church was created.","format":"date-time","type":"string"},"deletion":{"anyOf":[{"additionalProperties":false,"properties":{"purge_after":{"description":"When the data is removed.","format":"date-time","type":"string"},"requested_at":{"description":"When deletion was requested.","format":"date-time","type":"string"},"stage":{"description":"scheduled or purged.","enum":["scheduled","purged"],"type":"string"}},"required":["requested_at","purge_after","stage"],"type":"object"},{"type":"null"}],"description":"Set once deletion is scheduled."},"id":{"description":"The church id.","type":"string"},"name":{"description":"The church name.","type":"string"},"object":{"description":"Always church.","enum":["church"],"type":"string"},"plan":{"anyOf":[{"$ref":"#/components/schemas/WebhookPlanRef"},{"type":"null"}],"description":"The plan it is on, null before it has one."},"sandbox":{"description":"True for a free sandbox church that expires.","type":"boolean"},"slug":{"description":"The church web address.","type":"string"},"status":{"description":"Where the church stands.","enum":["active","suspended","deletion_scheduled","deleted"],"type":"string"},"subscription_status":{"description":"The subscription status, empty without a subscription.","type":"string"},"suspended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was suspended."}},"required":["id","object","name","slug","status","sandbox","country","plan","subscription_status","counts","suspended_at","deletion","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status, suspended_at.","type":"object"}},"type":"object"},"type":{"const":"partner.church.suspended"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"partner.church.suspended","tags":["Webhook events"],"x-group":"Partner"}},"partner.church.updated":{"post":{"description":"A customer church changed its name or web address.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `partner.church.updated`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_partner_church_updated","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A partner.church.updated event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"country":"GB","counts":{"members":6,"published_notes":96,"teachings":148},"created_at":"2026-10-13T09:12:10Z","deletion":{"purge_after":"2026-11-13T09:12:10Z","requested_at":"2026-10-13T09:12:10Z","stage":"scheduled"},"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"sandbox":false,"slug":"grace-place","status":"active","subscription_status":"active","suspended_at":"2026-10-13T09:12:10Z"},"previous_attributes":{"country":"Previous GB","name":"Previous Grace Place","slug":"Previous grace-place"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"partner.church.updated"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"country":{"description":"The ISO country code, empty when not set.","type":"string"},"counts":{"additionalProperties":false,"description":"How much the church holds.","properties":{"members":{"description":"Team members.","type":"integer"},"published_notes":{"description":"Published notes.","type":"integer"},"teachings":{"description":"Teachings in the library.","type":"integer"}},"required":["members","teachings","published_notes"],"type":"object"},"created_at":{"description":"When the church was created.","format":"date-time","type":"string"},"deletion":{"anyOf":[{"additionalProperties":false,"properties":{"purge_after":{"description":"When the data is removed.","format":"date-time","type":"string"},"requested_at":{"description":"When deletion was requested.","format":"date-time","type":"string"},"stage":{"description":"scheduled or purged.","enum":["scheduled","purged"],"type":"string"}},"required":["requested_at","purge_after","stage"],"type":"object"},{"type":"null"}],"description":"Set once deletion is scheduled."},"id":{"description":"The church id.","type":"string"},"name":{"description":"The church name.","type":"string"},"object":{"description":"Always church.","enum":["church"],"type":"string"},"plan":{"anyOf":[{"$ref":"#/components/schemas/WebhookPlanRef"},{"type":"null"}],"description":"The plan it is on, null before it has one."},"sandbox":{"description":"True for a free sandbox church that expires.","type":"boolean"},"slug":{"description":"The church web address.","type":"string"},"status":{"description":"Where the church stands.","enum":["active","suspended","deletion_scheduled","deleted"],"type":"string"},"subscription_status":{"description":"The subscription status, empty without a subscription.","type":"string"},"suspended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was suspended."}},"required":["id","object","name","slug","status","sandbox","country","plan","subscription_status","counts","suspended_at","deletion","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: name, slug, country.","type":"object"}},"type":"object"},"type":{"const":"partner.church.updated"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"partner.church.updated","tags":["Webhook events"],"x-group":"Partner"}},"partner.church.usage_threshold":{"post":{"description":"A customer church used up a share of one of its plan allowances.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `partner.church.usage_threshold`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_partner_church_usage_threshold","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A partner.church.usage_threshold event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"country":"GB","counts":{"members":6,"published_notes":96,"teachings":148},"created_at":"2026-10-13T09:12:10Z","deletion":{"purge_after":"2026-11-13T09:12:10Z","requested_at":"2026-10-13T09:12:10Z","stage":"scheduled"},"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","plan":{"id":"plan_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","key":"church","name":"Church","object":"plan"},"sandbox":false,"slug":"grace-place","status":"active","subscription_status":"active","suspended_at":"2026-10-13T09:12:10Z","usage_threshold":{"consumed":32,"included":40,"meter":"hours","percent":80,"period_start":"2026-10-13T09:12:10Z"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"partner.church.usage_threshold"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"country":{"description":"The ISO country code, empty when not set.","type":"string"},"counts":{"additionalProperties":false,"description":"How much the church holds.","properties":{"members":{"description":"Team members.","type":"integer"},"published_notes":{"description":"Published notes.","type":"integer"},"teachings":{"description":"Teachings in the library.","type":"integer"}},"required":["members","teachings","published_notes"],"type":"object"},"created_at":{"description":"When the church was created.","format":"date-time","type":"string"},"deletion":{"anyOf":[{"additionalProperties":false,"properties":{"purge_after":{"description":"When the data is removed.","format":"date-time","type":"string"},"requested_at":{"description":"When deletion was requested.","format":"date-time","type":"string"},"stage":{"description":"scheduled or purged.","enum":["scheduled","purged"],"type":"string"}},"required":["requested_at","purge_after","stage"],"type":"object"},{"type":"null"}],"description":"Set once deletion is scheduled."},"id":{"description":"The church id.","type":"string"},"name":{"description":"The church name.","type":"string"},"object":{"description":"Always church.","enum":["church"],"type":"string"},"plan":{"anyOf":[{"$ref":"#/components/schemas/WebhookPlanRef"},{"type":"null"}],"description":"The plan it is on, null before it has one."},"sandbox":{"description":"True for a free sandbox church that expires.","type":"boolean"},"slug":{"description":"The church web address.","type":"string"},"status":{"description":"Where the church stands.","enum":["active","suspended","deletion_scheduled","deleted"],"type":"string"},"subscription_status":{"description":"The subscription status, empty without a subscription.","type":"string"},"suspended_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was suspended."},"usage_threshold":{"additionalProperties":false,"description":"The allowance that crossed this share.","properties":{"consumed":{"description":"What has been used this period.","type":"integer"},"included":{"description":"What the plan includes, with credits.","type":"integer"},"meter":{"description":"The allowance, such as hours or asks.","type":"string"},"percent":{"description":"The share of the allowance used when this was sent: 80 or 100.","type":"integer"},"period_start":{"description":"The first day of the billing period.","format":"date-time","type":"string"}},"required":["meter","percent","consumed","included","period_start"],"type":"object"}},"required":["id","object","name","slug","status","sandbox","country","plan","subscription_status","counts","suspended_at","deletion","created_at","usage_threshold"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"partner.church.usage_threshold"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"partner.church.usage_threshold","tags":["Webhook events"],"x-group":"Partner"}},"partner.key.issued":{"post":{"description":"A partner issued an API key for a customer church. The secret is never included.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `partner.key.issued`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_partner_key_issued","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A partner.key.issued event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"church":{"id":"org_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Grace Place","object":"church","slug":"grace-place"},"church_ids":[],"created_at":"2026-10-13T09:12:10Z","created_by":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"expires_at":"2026-11-13T09:12:10Z","id":"key_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","last4":"a91c","mode":"live","name":"CRM sync","object":"api_key","partner":false,"prefix":"folio_live_3f9d","rate_limit_per_minute":600,"revoked_at":"2026-10-13T09:12:10Z","scopes":["teachings:read","notes:read"]}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"partner.key.issued"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The customer church the key belongs to, on partner keys."},"church_ids":{"description":"Customer churches a partner key may act for; empty means all.","items":{"description":"One value.","type":"string"},"type":"array"},"created_at":{"description":"When it was created.","format":"date-time","type":"string"},"created_by":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The team member who created it."},"expires_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the key stops working."},"id":{"description":"The API key id.","type":"string"},"last4":{"description":"The last four characters of the key.","type":"string"},"mode":{"description":"live or test.","enum":["live","test"],"type":"string"},"name":{"description":"The label given to the key.","type":"string"},"object":{"description":"Always api_key.","enum":["api_key"],"type":"string"},"partner":{"description":"True for a partner key.","type":"boolean"},"prefix":{"description":"The visible start of the key.","type":"string"},"rate_limit_per_minute":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The per-minute limit, null for the plan default."},"revoked_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was revoked."},"scopes":{"description":"The permissions it was given.","items":{"description":"One value.","type":"string"},"type":"array"}},"required":["id","object","name","prefix","last4","mode","scopes","partner","church_ids","rate_limit_per_minute","expires_at","revoked_at","created_by","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"partner.key.issued"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"partner.key.issued","tags":["Webhook events"],"x-group":"Partner"}},"scripture.indexed":{"post":{"description":"The scripture references in an approved note were found and linked to verses.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `scripture.indexed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_scripture_indexed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A scripture.indexed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"citation_count":14,"created_at":"2026-10-13T09:12:10Z","dropped_count":1,"finished_at":"2026-10-13T09:12:10Z","id":"ext_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","note":{"id":"note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"note","status":"approved"},"object":"scripture_extraction","status":"succeeded","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"scripture.indexed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"citation_count":{"description":"References that were verified and stored.","type":"integer"},"created_at":{"description":"When the run started.","format":"date-time","type":"string"},"dropped_count":{"description":"References that were set aside because they did not check out.","type":"integer"},"finished_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the run finished."},"id":{"description":"The extraction id.","type":"string"},"note":{"$ref":"#/components/schemas/WebhookNoteRef","description":"The note that was read."},"object":{"description":"Always scripture_extraction.","enum":["scripture_extraction"],"type":"string"},"status":{"description":"How the run ended.","enum":["queued","running","succeeded","failed"],"type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching the note belongs to."}},"required":["id","object","note","teaching","status","citation_count","dropped_count","created_at","finished_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"scripture.indexed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"scripture.indexed","tags":["Webhook events"],"x-group":"Scripture"}},"scripture.tension_detected":{"post":{"description":"A new teaching point seems to pull against earlier teaching on the same verse and needs a person to look.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `scripture.tension_detected`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_scripture_tension_detected","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A scripture.tension_detected event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"citation":{"id":"cit_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"citation","reference":"Romans 8:28","verse_id":28106},"created_at":"2026-10-13T09:12:10Z","id":"ten_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"tension","reason":"This point says the promise is conditional; earlier teaching says it is not.","status":"open","teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"}}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"scripture.tension_detected"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"citation":{"additionalProperties":false,"description":"The citation that conflicts.","properties":{"id":{"description":"The citation id.","type":"string"},"object":{"description":"Always citation.","enum":["citation"],"type":"string"},"reference":{"description":"The verse reference.","type":"string"},"verse_id":{"description":"The verse, numbered across the whole Bible.","type":"integer"}},"required":["id","object","verse_id","reference"],"type":"object"},"created_at":{"description":"When it was flagged.","format":"date-time","type":"string"},"id":{"description":"The tension id.","type":"string"},"object":{"description":"Always tension.","enum":["tension"],"type":"string"},"reason":{"description":"Why it was flagged, in one sentence.","type":"string"},"status":{"description":"Where review stands.","enum":["open","resolved","dismissed"],"type":"string"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching that raised it."}},"required":["id","object","citation","teaching","reason","status","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"scripture.tension_detected"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"scripture.tension_detected","tags":["Webhook events"],"x-group":"Scripture"}},"support.access_entered":{"post":{"description":"A Folio support person entered the church under a grant. Sent on every entry. entry_number counts them.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `support.access_entered`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_support_access_entered","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A support.access_entered event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","entry_number":1,"expires_at":"2026-10-13T09:12:10Z","first_entered_at":"2026-10-13T09:12:10Z","granted_by":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"id":"sup_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","include_ask":false,"object":"support_grant","revoked_at":"2026-10-13T09:12:10Z","scope":"read","status":"active"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"support.access_entered"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When it was granted.","format":"date-time","type":"string"},"entry_number":{"description":"On entry events, how many times the grant has been used including this one.","type":"integer"},"expires_at":{"description":"When the access ends on its own.","format":"date-time","type":"string"},"first_entered_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When support first used it."},"granted_by":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The owner who granted it."},"id":{"description":"The grant id.","type":"string"},"include_ask":{"description":"True when the grant also lets Folio support read Ask conversations.","type":"boolean"},"object":{"description":"Always support_grant.","enum":["support_grant"],"type":"string"},"revoked_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was revoked."},"scope":{"description":"read or edit.","enum":["read","edit"],"type":"string"},"status":{"description":"Where the grant stands.","enum":["active","revoked","expired"],"type":"string"}},"required":["id","object","scope","include_ask","status","granted_by","expires_at","first_entered_at","revoked_at","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"support.access_entered"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"support.access_entered","tags":["Webhook events"],"x-group":"Folio support access"}},"support.access_granted":{"post":{"description":"An owner let Folio support into the church for a limited time. The reason is not included.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `support.access_granted`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_support_access_granted","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A support.access_granted event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","entry_number":1,"expires_at":"2026-10-13T09:12:10Z","first_entered_at":"2026-10-13T09:12:10Z","granted_by":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"id":"sup_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","include_ask":false,"object":"support_grant","revoked_at":"2026-10-13T09:12:10Z","scope":"read","status":"active"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"support.access_granted"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When it was granted.","format":"date-time","type":"string"},"entry_number":{"description":"On entry events, how many times the grant has been used including this one.","type":"integer"},"expires_at":{"description":"When the access ends on its own.","format":"date-time","type":"string"},"first_entered_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When support first used it."},"granted_by":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The owner who granted it."},"id":{"description":"The grant id.","type":"string"},"include_ask":{"description":"True when the grant also lets Folio support read Ask conversations.","type":"boolean"},"object":{"description":"Always support_grant.","enum":["support_grant"],"type":"string"},"revoked_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was revoked."},"scope":{"description":"read or edit.","enum":["read","edit"],"type":"string"},"status":{"description":"Where the grant stands.","enum":["active","revoked","expired"],"type":"string"}},"required":["id","object","scope","include_ask","status","granted_by","expires_at","first_entered_at","revoked_at","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"support.access_granted"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"support.access_granted","tags":["Webhook events"],"x-group":"Folio support access"}},"support.access_revoked":{"post":{"description":"Support access ended because an owner revoked it or it reached its expiry. status says which.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `support.access_revoked`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_support_access_revoked","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A support.access_revoked event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","entry_number":1,"expires_at":"2026-10-13T09:12:10Z","first_entered_at":"2026-10-13T09:12:10Z","granted_by":{"id":"usr_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","object":"user"},"id":"sup_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","include_ask":false,"object":"support_grant","revoked_at":"2026-10-13T09:12:10Z","scope":"read","status":"active"},"previous_attributes":{"status":"revoked"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"support.access_revoked"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When it was granted.","format":"date-time","type":"string"},"entry_number":{"description":"On entry events, how many times the grant has been used including this one.","type":"integer"},"expires_at":{"description":"When the access ends on its own.","format":"date-time","type":"string"},"first_entered_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When support first used it."},"granted_by":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The owner who granted it."},"id":{"description":"The grant id.","type":"string"},"include_ask":{"description":"True when the grant also lets Folio support read Ask conversations.","type":"boolean"},"object":{"description":"Always support_grant.","enum":["support_grant"],"type":"string"},"revoked_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was revoked."},"scope":{"description":"read or edit.","enum":["read","edit"],"type":"string"},"status":{"description":"Where the grant stands.","enum":["active","revoked","expired"],"type":"string"}},"required":["id","object","scope","include_ask","status","granted_by","expires_at","first_entered_at","revoked_at","created_at"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"support.access_revoked"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"support.access_revoked","tags":["Webhook events"],"x-group":"Folio support access"}},"teaching.created":{"post":{"description":"A teaching was added by upload, link, YouTube, Drive or a finished live service.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `teaching.created`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_teaching_created","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A teaching.created event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","duration_seconds":2412,"failure_reason":"","guest_affiliation":"","id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","is_guest":false,"name":"Romans 8: Nothing can separate us","object":"teaching","passage":"Romans 8:31-39","possible_duplicate_of":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099","reason":"same recording length and transcript","title":"Romans 8: Nothing can separate us"},"progress":{"current":{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"},"needs_decision":false,"steps":[{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"}]},"recorded_at":"2026-10-11T10:00:00Z","series":"Romans","source":{"id":"src_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"upload","name":"Sunday uploads","object":"source"},"speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"ready","status_note":"","title":"Romans 8: Nothing can separate us","transcript_changed":false}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"teaching.created"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When the teaching was added.","format":"date-time","type":"string"},"duration_seconds":{"description":"The spoken length in seconds.","type":"integer"},"failure_reason":{"description":"A short plain reason when it failed, empty otherwise.","type":"string"},"guest_affiliation":{"description":"The guest speaker's church or organisation.","type":"string"},"id":{"description":"The teaching id.","type":"string"},"is_guest":{"description":"True when the speaker is a guest.","type":"boolean"},"name":{"description":"The teaching title, as every reference object names itself.","type":"string"},"object":{"description":"Always teaching.","enum":["teaching"],"type":"string"},"passage":{"description":"The main passage, empty when none was set.","type":"string"},"possible_duplicate_of":{"additionalProperties":false,"description":"A teaching Folio thinks this repeats.","properties":{"id":{"description":"The other teaching id.","type":"string"},"reason":{"description":"Why they look alike.","type":"string"},"title":{"description":"The other teaching title.","type":"string"}},"required":["id","title","reason"],"type":"object"},"progress":{"additionalProperties":false,"description":"How far processing has got.","properties":{"current":{"anyOf":[{"$ref":"#/components/schemas/WebhookProcessingStep"},{"type":"null"}],"description":"The step running now, null when none."},"needs_decision":{"description":"True when a person must decide something before it continues.","type":"boolean"},"steps":{"description":"The processing steps in order.","items":{"$ref":"#/components/schemas/WebhookProcessingStep"},"type":"array"}},"required":["steps","needs_decision","current"],"type":"object"},"recorded_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was recorded."},"series":{"description":"The series it belongs to, empty when none.","type":"string"},"source":{"anyOf":[{"$ref":"#/components/schemas/WebhookSourceRef"},{"type":"null"}],"description":"Where it came from, null for a one-off upload."},"speaker":{"description":"The speaker, empty when unknown.","type":"string"},"speaker_evidence":{"description":"Why Folio guessed that speaker, empty when it did not.","type":"string"},"speaker_inferred":{"description":"True when Folio guessed the speaker from the recording.","type":"boolean"},"status":{"description":"Where processing stands.","enum":["awaiting_upload","queued","ingested","resolving","processing","ready","failed"],"type":"string"},"status_note":{"description":"A short plain note about the current status.","type":"string"},"title":{"description":"The teaching title.","type":"string"},"transcript_changed":{"description":"True when the transcript was edited after the notes were written.","type":"boolean"}},"required":["id","object","name","title","passage","speaker","speaker_inferred","speaker_evidence","series","status","failure_reason","status_note","duration_seconds","created_at","recorded_at","source","transcript_changed","is_guest","guest_affiliation"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"teaching.created"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"teaching.created","tags":["Webhook events"],"x-group":"Teachings"}},"teaching.failed":{"post":{"description":"A teaching could not be processed.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `teaching.failed`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_teaching_failed","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A teaching.failed event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","duration_seconds":2412,"failure_reason":"","guest_affiliation":"","id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","is_guest":false,"name":"Romans 8: Nothing can separate us","object":"teaching","passage":"Romans 8:31-39","possible_duplicate_of":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099","reason":"same recording length and transcript","title":"Romans 8: Nothing can separate us"},"progress":{"current":{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"},"needs_decision":false,"steps":[{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"}]},"recorded_at":"2026-10-11T10:00:00Z","series":"Romans","source":{"id":"src_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"upload","name":"Sunday uploads","object":"source"},"speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"ready","status_note":"","title":"Romans 8: Nothing can separate us","transcript_changed":false},"previous_attributes":{"status":"awaiting_upload"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"teaching.failed"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When the teaching was added.","format":"date-time","type":"string"},"duration_seconds":{"description":"The spoken length in seconds.","type":"integer"},"failure_reason":{"description":"A short plain reason when it failed, empty otherwise.","type":"string"},"guest_affiliation":{"description":"The guest speaker's church or organisation.","type":"string"},"id":{"description":"The teaching id.","type":"string"},"is_guest":{"description":"True when the speaker is a guest.","type":"boolean"},"name":{"description":"The teaching title, as every reference object names itself.","type":"string"},"object":{"description":"Always teaching.","enum":["teaching"],"type":"string"},"passage":{"description":"The main passage, empty when none was set.","type":"string"},"possible_duplicate_of":{"additionalProperties":false,"description":"A teaching Folio thinks this repeats.","properties":{"id":{"description":"The other teaching id.","type":"string"},"reason":{"description":"Why they look alike.","type":"string"},"title":{"description":"The other teaching title.","type":"string"}},"required":["id","title","reason"],"type":"object"},"progress":{"additionalProperties":false,"description":"How far processing has got.","properties":{"current":{"anyOf":[{"$ref":"#/components/schemas/WebhookProcessingStep"},{"type":"null"}],"description":"The step running now, null when none."},"needs_decision":{"description":"True when a person must decide something before it continues.","type":"boolean"},"steps":{"description":"The processing steps in order.","items":{"$ref":"#/components/schemas/WebhookProcessingStep"},"type":"array"}},"required":["steps","needs_decision","current"],"type":"object"},"recorded_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was recorded."},"series":{"description":"The series it belongs to, empty when none.","type":"string"},"source":{"anyOf":[{"$ref":"#/components/schemas/WebhookSourceRef"},{"type":"null"}],"description":"Where it came from, null for a one-off upload."},"speaker":{"description":"The speaker, empty when unknown.","type":"string"},"speaker_evidence":{"description":"Why Folio guessed that speaker, empty when it did not.","type":"string"},"speaker_inferred":{"description":"True when Folio guessed the speaker from the recording.","type":"boolean"},"status":{"description":"Where processing stands.","enum":["awaiting_upload","queued","ingested","resolving","processing","ready","failed"],"type":"string"},"status_note":{"description":"A short plain note about the current status.","type":"string"},"title":{"description":"The teaching title.","type":"string"},"transcript_changed":{"description":"True when the transcript was edited after the notes were written.","type":"boolean"}},"required":["id","object","name","title","passage","speaker","speaker_inferred","speaker_evidence","series","status","failure_reason","status_note","duration_seconds","created_at","recorded_at","source","transcript_changed","is_guest","guest_affiliation"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status.","type":"object"}},"type":"object"},"type":{"const":"teaching.failed"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"teaching.failed","tags":["Webhook events"],"x-group":"Teachings"}},"teaching.ready":{"post":{"description":"A teaching finished processing and is searchable.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `teaching.ready`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_teaching_ready","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A teaching.ready event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","duration_seconds":2412,"failure_reason":"","guest_affiliation":"","id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","is_guest":false,"name":"Romans 8: Nothing can separate us","object":"teaching","passage":"Romans 8:31-39","possible_duplicate_of":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099","reason":"same recording length and transcript","title":"Romans 8: Nothing can separate us"},"progress":{"current":{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"},"needs_decision":false,"steps":[{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"}]},"recorded_at":"2026-10-11T10:00:00Z","series":"Romans","source":{"id":"src_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"upload","name":"Sunday uploads","object":"source"},"speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"ready","status_note":"","title":"Romans 8: Nothing can separate us","transcript_changed":false},"previous_attributes":{"duration_seconds":2411,"status":"awaiting_upload"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"teaching.ready"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When the teaching was added.","format":"date-time","type":"string"},"duration_seconds":{"description":"The spoken length in seconds.","type":"integer"},"failure_reason":{"description":"A short plain reason when it failed, empty otherwise.","type":"string"},"guest_affiliation":{"description":"The guest speaker's church or organisation.","type":"string"},"id":{"description":"The teaching id.","type":"string"},"is_guest":{"description":"True when the speaker is a guest.","type":"boolean"},"name":{"description":"The teaching title, as every reference object names itself.","type":"string"},"object":{"description":"Always teaching.","enum":["teaching"],"type":"string"},"passage":{"description":"The main passage, empty when none was set.","type":"string"},"possible_duplicate_of":{"additionalProperties":false,"description":"A teaching Folio thinks this repeats.","properties":{"id":{"description":"The other teaching id.","type":"string"},"reason":{"description":"Why they look alike.","type":"string"},"title":{"description":"The other teaching title.","type":"string"}},"required":["id","title","reason"],"type":"object"},"progress":{"additionalProperties":false,"description":"How far processing has got.","properties":{"current":{"anyOf":[{"$ref":"#/components/schemas/WebhookProcessingStep"},{"type":"null"}],"description":"The step running now, null when none."},"needs_decision":{"description":"True when a person must decide something before it continues.","type":"boolean"},"steps":{"description":"The processing steps in order.","items":{"$ref":"#/components/schemas/WebhookProcessingStep"},"type":"array"}},"required":["steps","needs_decision","current"],"type":"object"},"recorded_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was recorded."},"series":{"description":"The series it belongs to, empty when none.","type":"string"},"source":{"anyOf":[{"$ref":"#/components/schemas/WebhookSourceRef"},{"type":"null"}],"description":"Where it came from, null for a one-off upload."},"speaker":{"description":"The speaker, empty when unknown.","type":"string"},"speaker_evidence":{"description":"Why Folio guessed that speaker, empty when it did not.","type":"string"},"speaker_inferred":{"description":"True when Folio guessed the speaker from the recording.","type":"boolean"},"status":{"description":"Where processing stands.","enum":["awaiting_upload","queued","ingested","resolving","processing","ready","failed"],"type":"string"},"status_note":{"description":"A short plain note about the current status.","type":"string"},"title":{"description":"The teaching title.","type":"string"},"transcript_changed":{"description":"True when the transcript was edited after the notes were written.","type":"boolean"}},"required":["id","object","name","title","passage","speaker","speaker_inferred","speaker_evidence","series","status","failure_reason","status_note","duration_seconds","created_at","recorded_at","source","transcript_changed","is_guest","guest_affiliation"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: status, duration_seconds.","type":"object"}},"type":"object"},"type":{"const":"teaching.ready"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"teaching.ready","tags":["Webhook events"],"x-group":"Teachings"}},"teaching.retired":{"post":{"description":"A teaching was deleted from the library. The object is its last state.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `teaching.retired`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_teaching_retired","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A teaching.retired event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"created_at":"2026-10-13T09:12:10Z","duration_seconds":2412,"failure_reason":"","guest_affiliation":"","id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","is_guest":false,"name":"Romans 8: Nothing can separate us","object":"teaching","passage":"Romans 8:31-39","possible_duplicate_of":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099","reason":"same recording length and transcript","title":"Romans 8: Nothing can separate us"},"progress":{"current":{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"},"needs_decision":false,"steps":[{"finished_at":"2026-10-13T09:12:10Z","key":"transcribe","label":"Transcribing","note":"","started_at":"2026-10-13T09:12:10Z","state":"done"}]},"recorded_at":"2026-10-11T10:00:00Z","series":"Romans","source":{"id":"src_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","kind":"upload","name":"Sunday uploads","object":"source"},"speaker":"Pastor Ada Okafor","speaker_evidence":"","speaker_inferred":false,"status":"ready","status_note":"","title":"Romans 8: Nothing can separate us","transcript_changed":false}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"teaching.retired"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"created_at":{"description":"When the teaching was added.","format":"date-time","type":"string"},"duration_seconds":{"description":"The spoken length in seconds.","type":"integer"},"failure_reason":{"description":"A short plain reason when it failed, empty otherwise.","type":"string"},"guest_affiliation":{"description":"The guest speaker's church or organisation.","type":"string"},"id":{"description":"The teaching id.","type":"string"},"is_guest":{"description":"True when the speaker is a guest.","type":"boolean"},"name":{"description":"The teaching title, as every reference object names itself.","type":"string"},"object":{"description":"Always teaching.","enum":["teaching"],"type":"string"},"passage":{"description":"The main passage, empty when none was set.","type":"string"},"possible_duplicate_of":{"additionalProperties":false,"description":"A teaching Folio thinks this repeats.","properties":{"id":{"description":"The other teaching id.","type":"string"},"reason":{"description":"Why they look alike.","type":"string"},"title":{"description":"The other teaching title.","type":"string"}},"required":["id","title","reason"],"type":"object"},"progress":{"additionalProperties":false,"description":"How far processing has got.","properties":{"current":{"anyOf":[{"$ref":"#/components/schemas/WebhookProcessingStep"},{"type":"null"}],"description":"The step running now, null when none."},"needs_decision":{"description":"True when a person must decide something before it continues.","type":"boolean"},"steps":{"description":"The processing steps in order.","items":{"$ref":"#/components/schemas/WebhookProcessingStep"},"type":"array"}},"required":["steps","needs_decision","current"],"type":"object"},"recorded_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When it was recorded."},"series":{"description":"The series it belongs to, empty when none.","type":"string"},"source":{"anyOf":[{"$ref":"#/components/schemas/WebhookSourceRef"},{"type":"null"}],"description":"Where it came from, null for a one-off upload."},"speaker":{"description":"The speaker, empty when unknown.","type":"string"},"speaker_evidence":{"description":"Why Folio guessed that speaker, empty when it did not.","type":"string"},"speaker_inferred":{"description":"True when Folio guessed the speaker from the recording.","type":"boolean"},"status":{"description":"Where processing stands.","enum":["awaiting_upload","queued","ingested","resolving","processing","ready","failed"],"type":"string"},"status_note":{"description":"A short plain note about the current status.","type":"string"},"title":{"description":"The teaching title.","type":"string"},"transcript_changed":{"description":"True when the transcript was edited after the notes were written.","type":"boolean"}},"required":["id","object","name","title","passage","speaker","speaker_inferred","speaker_evidence","series","status","failure_reason","status_note","duration_seconds","created_at","recorded_at","source","transcript_changed","is_guest","guest_affiliation"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"teaching.retired"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"teaching.retired","tags":["Webhook events"],"x-group":"Teachings"}},"transcript.ready":{"post":{"description":"A transcript was stored and selected for a teaching.\n\nFolio sends this as a signed `POST` to every endpoint subscribed to `transcript.ready`. Verify the signature, answer with any 2xx within the timeout, and deduplicate on the `webhook-id` header; retries reuse it.","operationId":"webhook_transcript_ready","parameters":[{"description":"A unique id for this message. Retries reuse it.","example":"msg_01JC8M2X9R5V0K4T7E3Q6B1ZDN","in":"header","name":"webhook-id","required":true,"schema":{"type":"string"}},{"description":"Unix seconds when the message was signed. Reject anything more than five minutes from your clock.","example":"1767225600","in":"header","name":"webhook-timestamp","required":true,"schema":{"type":"string"}},{"description":"One or two space-separated v1,<base64 HMAC-SHA256> values over `<webhook-id>.<webhook-timestamp>.<raw body>`, keyed with the whsec_ secret.","example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2/3Wb9g5N1q0n1k=","in":"header","name":"webhook-signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"examples":{"default":{"summary":"A transcript.ready event","value":{"actor":null,"api_version":"2026-12-01","created":"2026-10-13T09:12:10Z","data":{"object":{"character_count":38214,"created_at":"2026-10-13T09:12:10Z","id":"trn_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","language":"en","object":"transcript","origin":"batch","segment_count":612,"teaching":{"id":"tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","name":"Romans 8: Nothing can separate us","object":"teaching","recorded_at":"2026-10-11T10:00:00Z","speaker":"Pastor Ada Okafor","title":"Romans 8: Nothing can separate us"},"url":"/v1/transcripts/trn_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012"}},"id":"evt_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012","livemode":false,"object":"event","request":{"id":"req_5f3c9a1e7b2d4c68a0e1f2d3c4b5a697","idempotency_key":null},"type":"transcript.ready"}}},"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"properties":{"data":{"properties":{"object":{"additionalProperties":false,"properties":{"character_count":{"description":"How many characters of text it holds.","type":"integer"},"created_at":{"description":"When it was stored.","format":"date-time","type":"string"},"id":{"description":"The transcript id.","type":"string"},"language":{"description":"The transcript language.","type":"string"},"object":{"description":"Always transcript.","enum":["transcript"],"type":"string"},"origin":{"description":"Where the words came from.","enum":["live","batch","captions_import","provider","manual"],"type":"string"},"segment_count":{"description":"How many timed segments it holds.","type":"integer"},"teaching":{"$ref":"#/components/schemas/WebhookTeachingRef","description":"The teaching it belongs to."},"url":{"description":"The API path that returns the full text.","type":"string"}},"required":["id","object","teaching","language","origin","segment_count","character_count","created_at","url"],"type":"object"},"previous_attributes":{"description":"Earlier values of changed fields: .","type":"object"}},"type":"object"},"type":{"const":"transcript.ready"}},"type":"object"}]}}},"required":true},"responses":{"2XX":{"description":"Acknowledge with any 2xx. Other answers and timeouts are retried on a backoff."}},"summary":"transcript.ready","tags":["Webhook events"],"x-group":"Teachings"}}},"components":{"schemas":{"AccessStandingWire":{"additionalProperties":false,"properties":{"converts":{"description":"True when a trial will start a paid plan on its end date because a card is on file.","type":"boolean"},"days_left":{"description":"Whole days left, rounded up. Zero once it has ended.","format":"int64","type":"integer"},"ends_at":{"description":"When the trial or pilot ends, or ended.","format":"date-time","type":["string","null"]},"expired_reason":{"description":"Why access ended: payment_failed after unpaid invoices ran out of grace, trial_ended for a trial or pilot, gift_ended for a gift. Empty unless the state is expired.","type":"string"},"grace_ends_at":{"description":"When a past-due church becomes read-only, or when it did. Set while past_due and after a payment_failed expiry.","format":"date-time","type":"string"},"has_card":{"description":"Whether a card is on file.","type":"boolean"},"kind":{"description":"Whether the access that is running, or ended, was a trial or a pilot. Empty on a paid plan.","type":"string"},"plan_name":{"description":"The plan whose allowances apply, or were applying when the trial ended.","type":"string"},"read_only":{"description":"True when new recordings, drafting, Ask and email sends are paused.","type":"boolean"},"state":{"description":"Where the church stands: a trial, pilot access, a paid plan, a payment to fix, an ended trial that is read-only, or nothing yet.","enum":["trial","pilot","paid","past_due","expired","none"],"type":"string"}},"required":["kind","plan_name","state","ends_at","days_left","has_card","read_only","converts"],"type":"object"},"AckBody":{"additionalProperties":false,"properties":{"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"ApiKeyWire":{"additionalProperties":false,"properties":{"church_ids":{"description":"Customer churches a partner key may act for. Empty means all.","items":{"type":"string"},"type":["array","null"]},"created_at":{"description":"When it was created, in RFC 3339 UTC.","type":"string"},"expires_at":{"description":"When it stops working, in RFC 3339 UTC.","type":["string","null"]},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"ip_allowlist":{"description":"Addresses or ranges the key accepts requests from. Empty means any address.","items":{"type":"string"},"type":["array","null"]},"last4":{"description":"The last four characters of the key.","type":"string"},"last_used_at":{"description":"When the key was last used, in RFC 3339 UTC.","type":["string","null"]},"last_used_ip":{"description":"The address of the last request.","type":"string"},"mode":{"description":"live or test.","type":"string"},"name":{"description":"The name.","type":"string"},"partner":{"description":"True for a partner key, which can act for the churches you operate.","type":"boolean"},"prefix":{"description":"The visible prefix of the key.","type":"string"},"rate_limit_per_minute":{"description":"An extra per-minute cap for this key, or null for none.","format":"int32","type":["integer","null"]},"request_count":{"description":"How many requests the key has made.","format":"int64","type":"integer"},"rotated_from":{"description":"The id of the key this one replaced, when it came from a rotation.","type":["string","null"]},"scopes":{"description":"The scopes the key carries.","items":{"type":"string"},"type":["array","null"]}},"type":"object"},"AskBlockWire":{"additionalProperties":false,"properties":{"church":{"description":"The church.","type":"string"},"resource":{"$ref":"#/components/schemas/Resource"},"source_refs":{"description":"The numbers of the sources this block draws on.","items":{"format":"int64","type":"integer"},"type":["array","null"]},"text":{"description":"The text.","type":"string"},"type":{"description":"The type.","type":"string"},"verse_ref":{"description":"The verse the block is about, as a reference.","type":"string"}},"required":["type","text","source_refs"],"type":"object"},"AskSourceWire":{"additionalProperties":false,"properties":{"at":{"description":"Where in the recording, as minutes and seconds.","type":"string"},"at_ms":{"description":"Where in the recording, in milliseconds.","format":"int64","type":"integer"},"church":{"description":"The church.","type":"string"},"excerpt":{"description":"The words from the teaching the answer drew on.","type":"string"},"guest":{"description":"Whether the speaker was a guest.","type":"boolean"},"guest_affiliation":{"description":"Where a guest speaker is from.","type":"string"},"number":{"description":"The number used to cite this source in the answer text.","format":"int64","type":"integer"},"quote_verified":{"description":"Whether the quoted words were checked against the transcript.","type":"boolean"},"recorded_on":{"description":"The date the teaching was recorded.","type":"string"},"series":{"description":"The series the teaching belongs to.","type":"string"},"speaker":{"description":"Who taught it.","type":"string"},"standing":{"description":"current, superseded or retracted.","type":"string"},"teaching_id":{"description":"The teaching id, prefixed tch_.","type":"string"},"title":{"description":"The title.","type":"string"}},"required":["number","title","excerpt"],"type":"object"},"AskWire":{"additionalProperties":false,"properties":{"conversation":{"$ref":"#/components/schemas/ConversationWire"},"turn":{"$ref":"#/components/schemas/TurnWire"}},"required":["conversation","turn"],"type":"object"},"BillingWire":{"additionalProperties":false,"properties":{"cycle":{"$ref":"#/components/schemas/CycleWire"},"entitlements":{"description":"What the plan allows.","items":{"$ref":"#/components/schemas/EntitlementWire"},"type":["array","null"]},"object":{"description":"The object type.","type":"string"},"plan":{"$ref":"#/components/schemas/PlanWire"},"standing":{"$ref":"#/components/schemas/AccessStandingWire"},"usage":{"description":"Token usage. Always zero.","items":{"$ref":"#/components/schemas/UsageWire"},"type":["array","null"]}},"required":["object","standing","plan","entitlements","usage","cycle"],"type":"object"},"ChatCompletion":{"additionalProperties":false,"properties":{"choices":{"description":"The completions.","items":{"$ref":"#/components/schemas/CompletionChoice"},"type":["array","null"]},"created":{"description":"When it was created, in Unix seconds.","format":"int64","type":"integer"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"model":{"description":"Accepted for compatibility and ignored.","type":"string"},"object":{"description":"The object type.","type":"string"},"usage":{"$ref":"#/components/schemas/CompletionUsage"}},"type":"object"},"ChatCompletionInputBody":{"additionalProperties":false,"properties":{"conversation_id":{"description":"Continue this conversation.","type":"string"},"messages":{"description":"The messages.","items":{"$ref":"#/components/schemas/CompletionMessage"},"type":["array","null"]},"model":{"description":"Accepted for compatibility and ignored.","type":"string"},"user":{"description":"An end-user identifier, for your own records.","type":"string"}},"type":"object"},"Chip":{"additionalProperties":false,"properties":{"ref":{"description":"A scripture reference such as Romans 8:28.","type":"string"},"status":{"description":"The current status.","type":"string"}},"type":"object"},"ClaimDevicePairingInputBody":{"additionalProperties":false,"properties":{"code":{"description":"A machine-readable code.","maxLength":6,"minLength":6,"type":"string"}},"type":"object"},"CompletionChoice":{"additionalProperties":false,"properties":{"finish_reason":{"description":"Why the answer ended.","type":"string"},"index":{"description":"The position in the list.","format":"int64","type":"integer"},"message":{"$ref":"#/components/schemas/CompletionMessage"}},"type":"object"},"CompletionMessage":{"additionalProperties":false,"properties":{"content":{"description":"The content.","type":"string"},"role":{"description":"user or assistant.","type":"string"}},"type":"object"},"CompletionUsage":{"additionalProperties":false,"properties":{"completion_tokens":{"description":"Always zero.","format":"int64","type":"integer"},"prompt_tokens":{"description":"Always zero.","format":"int64","type":"integer"},"total_tokens":{"description":"Always zero.","format":"int64","type":"integer"}},"type":"object"},"ConversationWire":{"additionalProperties":false,"properties":{"audience":{"description":"Who can see the conversation: private for keys.","type":"string"},"created_at":{"description":"When it was created, in RFC 3339 UTC.","format":"date-time","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"message_count":{"description":"How many messages the conversation holds.","format":"int32","type":"integer"},"messages":{"description":"The messages.","items":{"$ref":"#/components/schemas/MessageWire"},"type":["array","null"]},"mine":{"description":"Whether the calling credential started it.","type":"boolean"},"object":{"description":"The object type.","type":"string"},"scope":{"description":"What the answers may draw on."},"surface":{"description":"Where the conversation was started: machine for keys.","type":"string"},"title":{"description":"The title.","type":"string"},"updated_at":{"description":"When it last changed, in RFC 3339 UTC.","format":"date-time","type":"string"}},"required":["id","object","title","scope","surface","audience","message_count","mine","created_at","updated_at","messages"],"type":"object"},"CycleWire":{"additionalProperties":false,"properties":{"end":{"description":"When the billing cycle ends.","format":"date-time","type":"string"},"start":{"description":"When the billing cycle starts.","format":"date-time","type":"string"}},"required":["start","end"],"type":"object"},"DeliveryRow":{"additionalProperties":false,"properties":{"attempts":{"description":"How many delivery attempts have been made.","format":"int32","type":"integer"},"church":{"description":"The church."},"created_at":{"description":"When it was created, in RFC 3339 UTC.","type":"string"},"delivered_at":{"description":"When it was delivered, if it was.","type":["string","null"]},"event_id":{"description":"The id of the event that was delivered.","type":"string"},"event_type":{"description":"The event type, such as note.published.","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"last_error":{"description":"Why the last attempt failed.","type":"string"},"next_attempt_at":{"description":"When the next attempt happens, while retries remain.","type":["string","null"]},"object":{"description":"The object type.","type":"string"},"origin":{"description":"live or test.","type":"string"},"status":{"description":"The current status.","type":"string"}},"type":"object"},"DeviceCommandWire":{"additionalProperties":false,"properties":{"created_at":{"description":"When it was created, in RFC 3339 UTC.","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"kind":{"description":"The kind.","enum":["sync_now","update_available","revoke"],"type":"string"},"object":{"description":"The object type.","enum":["device_command"],"type":"string"},"payload":{"additionalProperties":{},"description":"Details for the command.","type":"object"},"seq":{"description":"The command's sequence number. Send the highest one as since.","format":"int64","type":"integer"}},"type":"object"},"DeviceCommandsWire":{"additionalProperties":false,"properties":{"commands":{"description":"Commands queued for the device after since.","items":{"$ref":"#/components/schemas/DeviceCommandWire"},"type":["array","null"]},"next_since":{"description":"Pass this as since on the next poll.","format":"int64","type":"integer"},"object":{"description":"The object type.","enum":["device_commands"],"type":"string"}},"type":"object"},"DeviceCompleteUploadInputBody":{"additionalProperties":false,"properties":{"key":{"description":"The key.","minLength":1,"type":"string"}},"type":"object"},"DeviceEventsInputBody":{"additionalProperties":false,"properties":{"events":{"description":"Up to 500 events to record.","items":{"$ref":"#/components/schemas/Item1"},"maxItems":500,"type":["array","null"]}},"type":"object"},"DeviceEventsWire":{"additionalProperties":false,"properties":{"object":{"description":"The object type.","enum":["device_events"],"type":"string"},"stored":{"description":"How many events were stored.","format":"int64","type":"integer"}},"type":"object"},"DeviceMeWire":{"additionalProperties":false,"properties":{"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"label":{"description":"The label shown to people.","type":"string"},"object":{"description":"The object type.","enum":["device"],"type":"string"},"org":{"description":"The church the device belongs to.","type":"string"},"scopes":{"description":"The scopes the key carries.","items":{"type":"string"},"type":["array","null"]}},"type":"object"},"DevicePacksWire":{"additionalProperties":false,"properties":{"object":{"description":"The object type.","enum":["device_packs"],"type":"string"},"songs":{"description":"Downloadable song packs.","items":{},"type":["array","null"]},"translations":{"description":"Downloadable scripture packs. King James Version only.","items":{},"type":["array","null"]}},"type":"object"},"DevicePairedWire":{"additionalProperties":false,"properties":{"device":{"description":"Device id (dev_...).","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"key":{"description":"The device key (folio_booth_...). Shown once.","type":"string"},"object":{"description":"The object type.","enum":["device_pairing"],"type":"string"},"paired":{"description":"Always true when pairing worked.","type":"boolean"}},"type":"object"},"DeviceTeachingInputBody":{"additionalProperties":false,"properties":{"content_type":{"description":"The media type of the recording, such as audio/mpeg.","minLength":1,"type":"string"},"filename":{"description":"The file name of the recording, used to keep the extension.","minLength":1,"type":"string"},"title":{"description":"The title.","maxLength":400,"minLength":1,"type":"string"}},"type":"object"},"DeviceUpdateWire":{"additionalProperties":false,"properties":{"contract":{"$ref":"#/components/schemas/DeviceUpdateWireContractStruct","description":"The X-Folio-Device-Contract versions this API accepts. Other values get 426."},"current":{"description":"The version the booth reported.","type":"string"},"latest":{"description":"The newest Folio Live version.","type":"string"},"min_supported":{"description":"The oldest version that still works.","type":"string"},"notes":{"description":"Release notes for the update.","type":"string"},"object":{"description":"The object type.","enum":["device_update"],"type":"string"},"platform":{"description":"windows, mac or linux.","type":"string"},"update_available":{"description":"Whether a newer version exists.","type":"boolean"},"update_required":{"description":"True when current is below min_supported. The booth must update before it can sync.","type":"boolean"},"url":{"description":"Where to download the build for this platform, when one is published.","type":"string"}},"type":"object"},"DeviceUpdateWireContractStruct":{"additionalProperties":false,"properties":{"current":{"description":"The newest contract version the API speaks.","format":"int64","type":"integer"},"minimum":{"description":"The oldest contract version accepted.","format":"int64","type":"integer"}},"type":"object"},"DeviceUploadDoneWire":{"additionalProperties":false,"properties":{"object":{"description":"The object type.","enum":["teaching"],"type":"string"},"teaching_id":{"description":"The teaching id, prefixed tch_.","type":"string"}},"type":"object"},"DeviceUploadWire":{"additionalProperties":false,"properties":{"expires_at":{"description":"When it stops working, in RFC 3339 UTC.","type":"string"},"key":{"description":"Send this back when completing the upload.","type":"string"},"object":{"description":"The object type.","enum":["upload"],"type":"string"},"teaching_id":{"description":"The teaching id, prefixed tch_.","type":"string"},"url":{"description":"Signed URL. PUT the recording bytes here with the same Content-Type.","type":"string"}},"type":"object"},"EntitlementWire":{"additionalProperties":false,"properties":{"feature":{"description":"The feature or meter the allowance applies to.","type":"string"},"quota":{"description":"How much the plan includes. Zero can mean the feature is on without a limit.","format":"int32","type":["integer","null"]}},"required":["feature","quota"],"type":"object"},"Envelope":{"description":"Every success response: status is true, message is a short label, data holds the result and meta holds paging details on lists.","properties":{"data":{"description":"The result. Its shape depends on the operation."},"message":{"description":"A short label for the result.","type":"string"},"meta":{"description":"Paging details on lists."},"status":{"description":"true for a success.","type":"boolean"}},"type":"object"},"ErrorBody":{"additionalProperties":false,"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"details":{"description":"Per-field problems.","items":{"$ref":"#/components/schemas/FieldError"},"type":["array","null"]},"meta":{"additionalProperties":{},"description":"Extra details.","type":"object"},"request_id":{"description":"Quote this when you contact support.","type":"string"},"status":{"description":"The current status.","format":"int64","type":"integer"}},"type":"object"},"ErrorCode":{"description":"The closed list of error codes. Branch on this, never on the message. New codes can be added within /v1, so treat unknown codes as a generic failure.","enum":["invalid_argument","unauthenticated","permission_denied","not_entitled","disabled_by_church","origin_not_allowed","not_found","already_exists","conflict","stale_version","failed_precondition","validation","rate_limited","step_up_required","quota_exceeded","plan_required","payment_failed","overage_ceiling_reached","ai_budget_exhausted","unavailable","internal"],"type":"string","x-enum-descriptions":{"invalid_argument":"The request could not be read: a malformed id, cursor, header or body.","unauthenticated":"The key is missing, malformed, revoked or expired.","permission_denied":"The key lacks the scope, the church is suspended, the address is outside the key's allowlist, or deletion is scheduled.","not_entitled":"The church's plan does not include this feature.","disabled_by_church":"The church turned this feature off in its own settings.","origin_not_allowed":"The page that called is not in the widget's allowlist.","not_found":"The thing is not in this church, or it is not visible yet (for example a note that is not published).","already_exists":"A thing with that identity already exists.","conflict":"The request clashes with the current state, including a duplicate Idempotency-Key still running.","stale_version":"The row changed since you read it, so your If-Match row_version is out of date (HTTP 412).","failed_precondition":"A required condition is not met yet.","validation":"A field failed validation, or an Idempotency-Key was reused with a different body (error.meta.reason is idempotency_key_reused).","rate_limited":"Too many requests for the key, the church or the device.","step_up_required":"The person must sign in again before this console action. It also answers a missing If-Match header (HTTP 428).","quota_exceeded":"The plan's allowance for hours, notes or Ask is used up (HTTP 402).","plan_required":"The church has no active plan for this action (HTTP 409).","payment_failed":"A payment did not go through.","overage_ceiling_reached":"Metered overage reached the ceiling the church set.","ai_budget_exhausted":"The church used its monthly AI budget, or a sandbox church used its test budget (HTTP 402).","unavailable":"A dependency is down or the church is not configured for this yet.","internal":"Something went wrong on Folio's side."}},"ErrorEnvelope":{"additionalProperties":false,"properties":{"error":{"$ref":"#/components/schemas/ErrorBody"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"EventCatalogueWire":{"additionalProperties":false,"properties":{"all":{"description":"Subscribe to this value to receive every event.","type":"string"},"api_version":{"description":"The event schema version these definitions describe.","type":"string"},"envelope":{"$ref":"#/components/schemas/EventEnvelopeWire"},"groups":{"description":"The groups of events.","items":{"$ref":"#/components/schemas/EventGroupWire"},"type":["array","null"]},"schemas":{"additionalProperties":{},"description":"Shared object schemas that event schemas reference as #/schemas/<name>.","type":"object"},"total":{"description":"The total number of items.","format":"int64","type":"integer"}},"type":"object"},"EventEnvelopeWire":{"additionalProperties":false,"properties":{"example":{"additionalProperties":{},"description":"A complete sample body.","type":"object"},"schema":{"additionalProperties":{},"description":"JSON Schema 2020-12 of the body Folio POSTs to your endpoint.","type":"object"}},"type":"object"},"EventGroupWire":{"additionalProperties":false,"properties":{"events":{"description":"The events to record.","items":{"$ref":"#/components/schemas/WebhookEventTypeWire"},"type":["array","null"]},"key":{"description":"The key.","type":"string"},"label":{"description":"The label shown to people.","type":"string"}},"type":"object"},"FieldError":{"additionalProperties":false,"properties":{"code":{"description":"A machine-readable code.","type":"string"},"field":{"description":"The field the problem is about.","type":"string"},"got":{"description":"The value that was sent."},"message":{"description":"A short label for the result.","type":"string"}},"type":"object"},"Item1":{"additionalProperties":false,"properties":{"at_ms":{"description":"When the event happened, in milliseconds since the epoch.","format":"int64","type":"integer"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","maxLength":120,"type":"string"},"kind":{"description":"The kind.","maxLength":40,"type":"string"},"payload":{"description":"Event details as a string, up to 4000 characters.","maxLength":4000,"type":"string"}},"type":"object"},"LibraryChangesWire":{"additionalProperties":false,"properties":{"more":{"description":"Whether another page of changes exists.","type":"boolean"},"next_since":{"description":"Pass as since on the next pull.","format":"int64","type":"integer"},"object":{"description":"The object type.","type":"string"},"objects":{"description":"The library objects.","items":{"$ref":"#/components/schemas/LibraryObjectWire"},"type":["array","null"]}},"type":"object"},"LibraryObjectWire":{"additionalProperties":false,"properties":{"body":{"description":"The object's content as JSON."},"deleted":{"description":"Whether it was deleted.","type":"boolean"},"hash":{"description":"A hash of the content, for change detection.","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"kind":{"description":"The kind.","type":"string"},"object":{"description":"The object type.","type":"string"},"revision":{"description":"The object's revision. Send it as base_revision when you write.","format":"int32","type":"integer"},"title":{"description":"The title.","type":"string"},"updated_at":{"description":"When it last changed, in RFC 3339 UTC.","type":"string"},"updated_by":{"description":"The id of whoever last changed it.","type":"string"},"updated_by_kind":{"description":"user or device.","type":"string"},"version":{"description":"The version.","format":"int64","type":"integer"}},"type":"object"},"LibraryPushInputBody":{"additionalProperties":false,"properties":{"objects":{"description":"The library objects.","items":{"$ref":"#/components/schemas/LibraryWriteWire"},"maxItems":100,"minItems":1,"type":["array","null"]}},"type":"object"},"LibraryPushWire":{"additionalProperties":false,"properties":{"object":{"description":"The object type.","type":"string"},"results":{"description":"One result per object written.","items":{"$ref":"#/components/schemas/LibraryResultWire"},"type":["array","null"]}},"type":"object"},"LibraryPutBody":{"additionalProperties":false,"properties":{"base_revision":{"description":"The revision you last read. 0 creates.","format":"int32","minimum":0,"type":"integer"},"body":{"description":"The object's content."},"checksum":{"description":"A checksum of the body you are sending.","maxLength":64,"type":"string"}},"type":"object"},"LibraryResultWire":{"additionalProperties":false,"properties":{"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"kind":{"description":"The kind.","type":"string"},"object":{"$ref":"#/components/schemas/LibraryObjectWire"},"outcome":{"description":"applied, conflict or rejected.","type":"string"},"reason":{"description":"The reason.","type":"string"}},"type":"object"},"LibraryWriteWire":{"additionalProperties":false,"properties":{"base_revision":{"description":"The revision you last read. 0 creates.","format":"int32","minimum":0,"type":"integer"},"body":{"description":"The object's content."},"checksum":{"description":"A checksum of the body you are sending.","maxLength":64,"type":"string"},"deleted":{"description":"Whether it was deleted.","type":"boolean"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","maxLength":64,"minLength":1,"type":"string"},"kind":{"description":"The kind.","enum":["song","theme","service_plan","service_record"],"type":"string"}},"type":"object"},"LinkWire":{"additionalProperties":false,"properties":{"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"incoming":{"description":"Whether the other church asked to link.","type":"boolean"},"object":{"description":"The object type.","type":"string"},"other_church":{"description":"The name of the other church.","type":"string"},"other_slug":{"description":"The other church's slug.","type":"string"},"requested_label":{"description":"The label the request asked for.","type":"string"},"requester_org":{"description":"The church that asked.","type":"string"},"status":{"description":"The current status.","type":"string"},"target_org":{"description":"The church that was asked.","type":"string"}},"type":"object"},"ListMeta":{"description":"Paging details that come with every list.","properties":{"has_next":{"description":"Whether another page exists.","type":"boolean"},"has_prev":{"description":"Whether this is not the first page.","type":"boolean"},"next_cursor":{"description":"Pass as cursor to get the next page. Present only when has_next is true.","type":"string"},"request_id":{"description":"Quote this when you contact support. It is also in the X-Request-Id header.","type":"string"},"total":{"description":"The total number of matching items, on lists that know it.","type":"integer"}},"type":"object"},"LookupWire":{"additionalProperties":false,"properties":{"book":{"description":"The book of the Bible.","type":"string"},"chapter":{"description":"The chapter number.","format":"int64","type":"integer"},"items":{"description":"The teachings that quote the passage.","items":{"$ref":"#/components/schemas/TaughtItemWire"},"type":["array","null"]},"items_truncated":{"description":"Whether the list of teachings was cut short.","type":"boolean"},"notice":{"description":"A note about the passage, when there is one.","type":"string"},"object":{"description":"The object type.","type":"string"},"open_tensions":{"description":"How many unresolved differences between teachings the church has on the passage.","format":"int64","type":"integer"},"ref":{"description":"A scripture reference such as Romans 8:28.","type":"string"},"summaries":{"description":"A summary for each verse.","items":{"$ref":"#/components/schemas/VerseSummaryItemWire"},"type":["array","null"]},"taught":{"$ref":"#/components/schemas/TaughtWire"},"translation":{"description":"The translation code. Folio has KJV only.","type":"string"},"verse_end":{"description":"The last verse of the passage.","format":"int64","type":"integer"},"verse_start":{"description":"The first verse of the passage.","format":"int64","type":"integer"},"verses":{"description":"The verses.","items":{"$ref":"#/components/schemas/VerseTextWire"},"type":["array","null"]},"whole_chapter":{"description":"Whether the reference was a whole chapter.","type":"boolean"}},"required":["object","ref","book","chapter","verse_start","verse_end","whole_chapter","translation","verses","taught","items","items_truncated","summaries","open_tensions","notice"],"type":"object"},"MachineAttemptWire":{"additionalProperties":false,"properties":{"attempt_number":{"description":"Which attempt this was.","format":"int32","type":"integer"},"created_at":{"description":"When it was created, in RFC 3339 UTC.","type":"string"},"duration_ms":{"description":"How long your receiver took, in milliseconds.","format":"int32","type":"integer"},"error_code":{"description":"A short code when the attempt failed before an answer.","type":"string"},"error_message":{"description":"A short reason when the attempt failed before an answer.","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"object":{"description":"The object type.","enum":["webhook_attempt"],"type":"string"},"request_body":{"description":"Exactly what was sent. Removed after 30 days."},"request_headers":{"additionalProperties":{"type":"string"},"description":"The signature is shortened.","type":"object"},"response_body":{"description":"First 2 KB of the answer, with secrets removed.","type":"string"},"response_code":{"description":"The HTTP status your receiver answered with.","format":"int32","type":"integer"},"signed_at":{"description":"When the message was signed.","type":"string"},"trigger":{"description":"What caused the attempt: auto, retry or replay.","type":"string"}},"type":"object"},"MachineCareAlertWire":{"additionalProperties":false,"properties":{"category":{"description":"The kind of care alert.","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"object":{"description":"The object type.","enum":["care_alert"],"type":"string"},"status":{"description":"The current status.","type":"string"},"urgency":{"description":"How fast a person should respond.","type":"string"}},"type":"object"},"MachineCompleteUploadInputBody":{"additionalProperties":false,"properties":{"key":{"description":"The key.","minLength":1,"type":"string"}},"type":"object"},"MachineCreateConversationInputBody":{"additionalProperties":false,"properties":{"input":{"description":"The question.","maxLength":2000,"type":"string"},"scope":{"$ref":"#/components/schemas/Scope"},"title":{"description":"The title.","maxLength":200,"type":"string"}},"type":"object"},"MachineCreateMessageInputBody":{"additionalProperties":false,"properties":{"input":{"description":"The question.","maxLength":2000,"minLength":1,"type":"string"},"stream":{"description":"Streaming is not supported.","type":"boolean"}},"type":"object"},"MachineCreateTeachingInputBody":{"additionalProperties":false,"properties":{"content_type":{"description":"The media type of the recording, such as audio/mpeg.","minLength":1,"type":"string"},"filename":{"description":"The file name of the recording, used to keep the extension.","minLength":1,"type":"string"},"title":{"description":"The title.","maxLength":400,"minLength":1,"type":"string"}},"type":"object"},"MachineEndpointCreateInputBody":{"additionalProperties":false,"properties":{"child_scope":{"description":"Partner keys: also receive customer churches' events.","enum":["none","all","selected"],"type":"string"},"church_ids":{"description":"The customer churches this applies to.","items":{"type":"string"},"maxItems":500,"type":["array","null"]},"event_types":{"description":"Event types from GET /v1/webhook-event-types, or * for every event.","items":{"type":"string"},"type":["array","null"]},"mode":{"description":"live or test.","enum":["live","test"],"type":"string"},"name":{"description":"The name.","type":"string"},"url":{"description":"A public https URL.","type":"string"}},"type":"object"},"MachineEndpointCreatedWire":{"additionalProperties":false,"properties":{"endpoint":{"$ref":"#/components/schemas/WebhookEndpointWire"},"secret":{"description":"The signing secret. Shown once.","type":"string"}},"type":"object"},"MachineEndpointDeletedWire":{"additionalProperties":false,"properties":{"deleted":{"description":"Whether it was deleted.","type":"boolean"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"}},"type":"object"},"MachineEndpointRotatedWire":{"additionalProperties":false,"properties":{"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"prev_expires_in_hours":{"description":"The previous secret keeps signing alongside the new one for this long.","format":"int64","type":"integer"},"secret":{"description":"The new signing secret. Shown once.","type":"string"}},"type":"object"},"MachineEndpointTestInputBody":{"additionalProperties":false,"properties":{"event_type":{"description":"Send this event type's example. Leave empty for a generic test.","type":"string"}},"type":"object"},"MachineEndpointTestWire":{"additionalProperties":false,"properties":{"delivered":{"description":"Whether your receiver answered 2xx.","type":"boolean"},"delivery":{"description":"The id of the test delivery.","type":"string"},"status":{"description":"HTTP status your endpoint answered with.","format":"int64","type":"integer"},"test":{"description":"Always true for a test delivery.","type":"boolean"}},"type":"object"},"MachineEndpointUpdateInputBody":{"additionalProperties":false,"properties":{"child_scope":{"description":"none, all or selected: whether a partner endpoint also receives customer churches' events.","enum":["none","all","selected"],"type":"string"},"church_ids":{"description":"The customer churches this applies to.","items":{"type":"string"},"maxItems":500,"type":["array","null"]},"dedupe":{"additionalProperties":{},"description":"Deduplication settings.","type":"object"},"event_types":{"description":"The event types, or * for all.","items":{"type":"string"},"type":["array","null"]},"filter":{"additionalProperties":{},"description":"Filter settings.","type":"object"},"mode":{"description":"live or test.","enum":["live","test"],"type":"string"},"name":{"description":"The name.","type":"string"},"shape":{"additionalProperties":{},"description":"Payload shaping settings.","type":"object"},"url":{"description":"The URL.","type":"string"}},"type":"object"},"MachineNoteWire":{"additionalProperties":false,"properties":{"approval_kind":{"description":"How it was approved: human when a reviewer read it, automatic when the church's automatic approval did. Null when not approved.","type":["string","null"]},"approved_at":{"description":"When it was approved.","format":"date-time","type":["string","null"]},"church":{"description":"The church name.","type":"string"},"created_at":{"description":"When the first version was written.","format":"date-time","type":"string"},"id":{"description":"The note id, prefixed note_.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"published_at":{"description":"When it was published.","format":"date-time","type":["string","null"]},"sections":{"description":"The note body in order. Each section has a heading (h) and a body.","items":{"$ref":"#/components/schemas/Section"},"type":["array","null"]},"share_path":{"description":"The path of the published share page on the church's public site.","type":"string"},"share_slug":{"description":"The slug of the published share page.","type":"string"},"speaker":{"description":"Who taught it.","type":"string"},"status":{"description":"The note status. Keys only see published notes.","type":"string"},"summary":{"description":"A short summary of the teaching.","type":"string"},"teaching":{"$ref":"#/components/schemas/Ref","description":"The teaching the note was written from."},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"}},"type":"object"},"MachineOutputWire":{"additionalProperties":false,"properties":{"body_md":{"description":"The full text as Markdown.","type":"string"},"id":{"description":"The output id, prefixed out_.","type":"string"},"kind":{"description":"What it is.","enum":["devotional","blog","newsletter","study_guide"],"type":"string"},"language":{"description":"The language code.","type":"string"},"meta":{"additionalProperties":{"type":"string"},"description":"Extra fields for the kind, such as a subject line for a newsletter.","type":"object"},"note_id":{"description":"The note it was written from.","type":["string","null"]},"object":{"description":"Always output.","enum":["output"],"type":"string"},"status":{"description":"The output status. Keys only see published outputs.","type":"string"},"teaching_id":{"description":"The teaching it was written from.","type":"string"},"title":{"description":"The title.","type":"string"},"updated_at":{"description":"When it last changed.","format":"date-time","type":"string"},"verses":{"description":"The passages it quotes, checked against the King James Version.","items":{"$ref":"#/components/schemas/Chip"},"type":["array","null"]},"word_count":{"description":"The length in words.","format":"int64","type":"integer"}},"type":"object"},"MachineSegmentWire":{"additionalProperties":false,"properties":{"end_ms":{"description":"Where the segment ends, in milliseconds.","format":"int64","type":"integer"},"object":{"description":"Always segment.","enum":["segment"],"type":"string"},"speaker":{"description":"The speaker label, when the recording was split by speaker.","type":"string"},"start_ms":{"description":"Where the segment starts, in milliseconds from the start of the recording.","format":"int64","type":"integer"},"text":{"description":"What was said.","type":"string"}},"type":"object"},"MachineSubscriberWire":{"additionalProperties":false,"properties":{"email":{"description":"The email address.","type":"string"},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"object":{"description":"The object type.","enum":["subscriber"],"type":"string"},"status":{"description":"The current status.","type":"string"}},"type":"object"},"MachineTeachingWire":{"additionalProperties":false,"properties":{"created_at":{"description":"When the teaching was added.","format":"date-time","type":"string"},"duration_seconds":{"description":"The spoken length in seconds. Zero until the recording is read.","format":"int32","type":"integer"},"failure_reason":{"description":"A short, plain reason when status is failed. Empty otherwise.","type":"string"},"id":{"description":"The teaching id, prefixed tch_.","type":"string"},"note_id":{"description":"The note written from it, prefixed note_. Null until a note exists.","type":["string","null"]},"note_status":{"description":"The status of that note: none, draft, in_review, approved, published, failed or superseded.","type":"string"},"object":{"description":"Always teaching.","enum":["teaching"],"type":"string"},"passage":{"description":"The main passage, as a reference such as Romans 8:28-39. Empty until known.","type":"string"},"recorded_at":{"description":"When the teaching was given, when known.","format":"date-time","type":["string","null"]},"series":{"description":"The series it belongs to. Empty when it is not part of one.","type":"string"},"speaker":{"description":"Who taught it. Empty until known.","type":"string"},"status":{"description":"Where the teaching is: awaiting_upload, queued, processing, ready or failed. Only ready teachings have a transcript and a note.","type":"string"},"title":{"description":"The teaching title.","type":"string"}},"type":"object"},"MessageWire":{"additionalProperties":false,"properties":{"blocks":{"description":"The answer in blocks.","items":{"$ref":"#/components/schemas/AskBlockWire"},"type":["array","null"]},"created_at":{"description":"When it was created, in RFC 3339 UTC.","format":"date-time","type":"string"},"follow_ups":{"description":"Questions the reader may ask next.","items":{"type":"string"},"type":["array","null"]},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"kind":{"description":"The kind.","type":"string"},"next_steps":{"description":"Suggested next actions for the reader.","items":{"$ref":"#/components/schemas/NextStepWire"},"type":["array","null"]},"object":{"description":"The object type.","type":"string"},"role":{"description":"user or assistant.","type":"string"},"shareable":{"description":"Whether the answer can be shared by link.","type":"boolean"},"short_answer":{"description":"A one or two sentence answer.","type":"string"},"sources":{"description":"The sources the answer is drawn from.","items":{"$ref":"#/components/schemas/AskSourceWire"},"type":["array","null"]},"standing":{"description":"Whether the teachings an answer drew on are current, superseded or retracted.","items":{"$ref":"#/components/schemas/StandingWire"},"type":["array","null"]},"text":{"description":"The text.","type":"string"},"trace":{"$ref":"#/components/schemas/TraceWire"},"verses":{"description":"The verses.","items":{"$ref":"#/components/schemas/VerseUseWire"},"type":["array","null"]}},"required":["id","object","role","kind","blocks","follow_ups","sources","standing","next_steps","shareable","created_at"],"type":"object"},"MeterPriceWire":{"additionalProperties":false,"properties":{"amount":{"description":"The price in the smallest currency unit for per units.","format":"int64","type":"integer"},"currency":{"description":"The ISO 4217 currency code.","type":"string"},"meter":{"description":"What is metered, such as hours.","type":"string"},"per":{"description":"Units of usage the amount covers: 60 for hours (minutes), 1000 for emails, otherwise 1.","format":"int64","type":"integer"},"tiers":{"description":"Per-church volume tiers for the network plan."}},"required":["meter","currency","amount","per"],"type":"object"},"NextStepWire":{"additionalProperties":false,"properties":{"kind":{"description":"The kind.","type":"string"},"label":{"description":"The label shown to people.","type":"string"}},"required":["kind","label"],"type":"object"},"PageMeta":{"additionalProperties":false,"properties":{"has_next":{"description":"Whether another page exists.","type":"boolean"},"has_prev":{"description":"Whether this is not the first page.","type":"boolean"},"next_cursor":{"description":"The cursor for the next page.","type":"string"},"request_id":{"description":"Quote this when you contact support.","type":"string"},"total":{"description":"The total number of items.","format":"int64","type":"integer"}},"type":"object"},"PartnerChurchWire":{"additionalProperties":false,"properties":{"admin_email":{"description":"The first administrator's email address.","type":"string"},"church_id":{"description":"Church id (org_...) to use in the key routes.","type":"string"},"expires_at":{"description":"Sandbox churches are deleted at this time.","type":["string","null"]},"id":{"description":"Sub-account id (sac_...).","type":"string"},"name":{"description":"The name.","type":"string"},"object":{"description":"The object type.","enum":["church"],"type":"string"},"sandbox":{"description":"True for a free sandbox church that only takes folio_test_ keys.","type":"boolean"},"slug":{"description":"The slug used in public URLs.","type":"string"}},"type":"object"},"PartnerCreateChurchInputBody":{"additionalProperties":false,"properties":{"admin_email":{"description":"The email address of the church's first administrator.","format":"email","type":"string"},"name":{"description":"The name.","maxLength":120,"minLength":2,"type":"string"},"sandbox":{"description":"Create a free sandbox church for testing. It takes only folio_test_ keys, has hard limits and is deleted after 30 days.","type":"boolean"},"slug":{"description":"The slug used in public URLs.","maxLength":60,"type":"string"}},"type":"object"},"PartnerIssueKeyInputBody":{"additionalProperties":false,"properties":{"name":{"description":"The name.","type":"string"},"scopes":{"description":"The scopes the key carries.","items":{"type":"string"},"type":["array","null"]}},"type":"object"},"PartnerKeyIssuedWire":{"additionalProperties":false,"properties":{"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"key":{"description":"The full key. Shown once.","type":"string"},"mode":{"description":"live or test.","enum":["live","test"],"type":"string"},"name":{"description":"The name.","type":"string"},"object":{"description":"The object type.","enum":["api_key"],"type":"string"},"scopes":{"description":"The scopes the key carries.","items":{"type":"string"},"type":["array","null"]}},"type":"object"},"PartnerOverviewWire":{"additionalProperties":false,"properties":{"churches":{"description":"How many customer churches the partner runs.","format":"int64","type":"integer"},"grants":{"description":"The programme features the partner has.","items":{"type":"string"},"type":["array","null"]},"is_partner":{"description":"Whether the church is a partner.","type":"boolean"}},"type":"object"},"PlanCatalogueWire":{"additionalProperties":false,"properties":{"entitlements":{"description":"What the plan allows.","items":{"$ref":"#/components/schemas/EntitlementWire"},"type":["array","null"]},"key":{"description":"The key.","type":"string"},"meter_prices":{"description":"Prices for usage beyond the allowance.","items":{"$ref":"#/components/schemas/MeterPriceWire"},"type":["array","null"]},"name":{"description":"The name.","type":"string"},"prices":{"description":"Prices per interval and currency.","items":{"$ref":"#/components/schemas/PriceWire"},"type":["array","null"]},"version":{"description":"The version.","format":"int32","type":"integer"}},"required":["key","name","version","prices","entitlements","meter_prices"],"type":"object"},"PlanWire":{"additionalProperties":false,"properties":{"key":{"description":"The key.","type":"string"},"name":{"description":"The name.","type":"string"},"version":{"description":"The version.","format":"int32","type":"integer"}},"required":["key","name","version"],"type":"object"},"PriceWire":{"additionalProperties":false,"properties":{"amount":{"description":"The price in the smallest currency unit.","format":"int64","type":"integer"},"currency":{"description":"The ISO 4217 currency code.","type":"string"},"interval":{"description":"month or year.","type":"string"},"region":{"description":"The pricing region, when prices differ by region.","type":"string"}},"required":["interval","currency","region","amount"],"type":"object"},"PublicAskTurnInputBody":{"additionalProperties":false,"properties":{"note_slug":{"description":"Ask about this published note.","maxLength":120,"type":"string"},"question":{"description":"The question, up to 1000 characters.","maxLength":1000,"minLength":1,"type":"string"},"session":{"description":"An anonymous visitor id you generate: 16 to 128 URL-safe characters.","pattern":"^[A-Za-z0-9_-]{16,128}$","type":"string"}},"type":"object"},"Ref":{"additionalProperties":false,"properties":{"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"name":{"description":"The name.","type":"string"},"object":{"description":"The object type.","type":"string"}},"type":"object"},"Resource":{"additionalProperties":false,"properties":{"country":{"description":"The country the contact is for.","type":"string"},"description":{"description":"A description.","type":"string"},"dial":{"description":"The number to call.","type":"string"},"hours":{"description":"When the contact is available.","type":"string"},"name":{"description":"The name.","type":"string"},"phone":{"description":"The phone number.","type":"string"},"url":{"description":"The URL.","type":"string"}},"required":["name"],"type":"object"},"Scope":{"additionalProperties":false,"properties":{"campus":{"description":"A campus id.","type":"string"},"campus_mode":{"description":"How the campus filter applies.","type":"string"},"include_guests":{"description":"Whether guest speakers' teaching may be used.","type":"boolean"},"kind":{"description":"The kind.","type":"string"},"language":{"description":"The language code.","type":"string"},"library":{"description":"Which library the answer may draw on.","type":"string"},"refs":{"description":"Passages or teachings the conversation is about.","items":{"type":"string"},"type":["array","null"]},"speakers":{"description":"Only teaching by these speakers.","items":{"type":"string"},"type":["array","null"]}},"type":"object"},"Section":{"additionalProperties":false,"properties":{"body":{"description":"The section text.","type":"string"},"h":{"description":"The section heading.","type":"string"}},"type":"object"},"StandingWire":{"additionalProperties":false,"properties":{"note":{"description":"Why the teaching's standing changed.","type":"string"},"replacement_title":{"description":"The title of the teaching that replaced this one.","type":"string"},"state":{"description":"current, superseded or retracted.","type":"string"},"superseded_by":{"description":"The teaching that replaced this one.","type":"string"},"teaching_id":{"description":"The teaching this is about.","type":"string"},"title":{"description":"The title.","type":"string"}},"required":["teaching_id","state"],"type":"object"},"SubscribeInputBody":{"additionalProperties":false,"properties":{"email":{"description":"The email address.","type":"string"},"first_name":{"description":"The subscriber's first name.","type":"string"},"source":{"description":"Where the signup came from, such as website.","type":"string"}},"type":"object"},"TaughtItemWire":{"additionalProperties":false,"properties":{"anchored":{"description":"Whether the quote is tied to a moment in the recording.","type":"boolean"},"citation_id":{"description":"The id of the citation.","type":"string"},"excerpt":{"description":"The words the teaching used about the passage.","type":"string"},"guest_affiliation":{"description":"Where a guest speaker is from.","type":"string"},"is_guest":{"description":"Whether the speaker was a guest.","type":"boolean"},"point":{"description":"The point the teaching made about the passage.","type":"string"},"reference":{"description":"The passage as the teaching cited it.","type":"string"},"speaker":{"description":"Who taught it.","type":"string"},"start_s":{"description":"Where in the recording the passage starts, in seconds.","format":"int32","type":["integer","null"]},"taught_at":{"description":"When it was taught.","type":"string"},"teaching_id":{"description":"The teaching, prefixed tch_.","type":"string"},"title":{"description":"The title.","type":"string"}},"required":["citation_id","teaching_id","title","speaker","taught_at","reference","point","excerpt","start_s","anchored","is_guest","guest_affiliation"],"type":"object"},"TaughtWire":{"additionalProperties":false,"properties":{"by_year":{"description":"Teachings per year.","items":{"$ref":"#/components/schemas/YearCountWire"},"type":["array","null"]},"first_year":{"description":"The first year the church taught the passage.","format":"int64","type":"integer"},"last_year":{"description":"The latest year the church taught the passage.","format":"int64","type":"integer"},"preachers":{"description":"How many different preachers taught it.","format":"int64","type":"integer"},"teachings":{"description":"How many teachings quote the passage.","format":"int64","type":"integer"}},"required":["teachings","preachers","first_year","last_year","by_year"],"type":"object"},"TraceStep":{"additionalProperties":false,"properties":{"count":{"description":"The number of items.","format":"int64","type":"integer"},"detail":{"description":"A short description of the step.","type":"string"},"items":{"description":"The teachings that quote the passage.","items":{"type":"string"},"type":["array","null"]},"stage":{"description":"Which step of the answer this was.","type":"string"},"title":{"description":"The title.","type":"string"}},"required":["stage","title"],"type":"object"},"TraceWire":{"additionalProperties":false,"properties":{"steps":{"description":"The steps taken to answer.","items":{"$ref":"#/components/schemas/TraceStep"},"type":["array","null"]},"thoughts":{"description":"A summary of how the answer was put together.","type":"string"}},"required":["steps"],"type":"object"},"TurnWire":{"additionalProperties":false,"properties":{"answer":{"$ref":"#/components/schemas/MessageWire"},"question":{"$ref":"#/components/schemas/MessageWire"}},"required":["question","answer"],"type":"object"},"TypedBodyDeviceCommandWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DeviceCommandWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDeviceCommandsWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DeviceCommandsWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDeviceEventsWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DeviceEventsWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDeviceMeWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DeviceMeWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDevicePacksWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DevicePacksWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDevicePairedWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DevicePairedWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDeviceUpdateWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DeviceUpdateWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDeviceUploadDoneWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DeviceUploadDoneWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyDeviceUploadWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/DeviceUploadWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyEventCatalogueWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/EventCatalogueWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyLibraryChangesWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/LibraryChangesWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyLibraryObjectWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/LibraryObjectWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyLibraryPushWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/LibraryPushWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyMachineEndpointCreatedWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/MachineEndpointCreatedWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyMachineEndpointDeletedWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/MachineEndpointDeletedWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyMachineEndpointRotatedWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/MachineEndpointRotatedWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyMachineEndpointTestWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/MachineEndpointTestWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyPartnerChurchWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/PartnerChurchWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyPartnerKeyIssuedWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/PartnerKeyIssuedWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyPartnerOverviewWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/PartnerOverviewWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyRawMessage":{"additionalProperties":false,"properties":{"data":{"description":"The result."},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedBodyWebhookEndpointWire":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/WebhookEndpointWire"},"message":{"description":"A short label for the result.","type":"string"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyApiKeyWire":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/ApiKeyWire"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyDeliveryRow":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/DeliveryRow"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyLinkWire":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/LinkWire"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyMachineAttemptWire":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/MachineAttemptWire"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyMachineCareAlertWire":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/MachineCareAlertWire"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyMachineSubscriberWire":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/MachineSubscriberWire"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyPartnerChurchWire":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/PartnerChurchWire"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"TypedListBodyWebhookEndpointWire":{"additionalProperties":false,"properties":{"data":{"description":"The result.","items":{"$ref":"#/components/schemas/WebhookEndpointWire"},"type":["array","null"]},"message":{"description":"A short label for the result.","type":"string"},"meta":{"$ref":"#/components/schemas/PageMeta"},"status":{"description":"The current status.","type":"boolean"}},"type":"object"},"UsageWire":{"additionalProperties":false,"properties":{"consumed":{"description":"How much has been used.","format":"int64","type":"integer"},"included":{"description":"How much the plan includes.","format":"int32","type":["integer","null"]},"meter":{"description":"What is metered, such as hours.","type":"string"},"unit":{"description":"What consumed and included are counted in. The hours meter is counted in minutes.","enum":["count","minutes","gb"],"type":"string"}},"required":["meter","unit","consumed","included"],"type":"object"},"VerseSummaryItemWire":{"additionalProperties":false,"properties":{"preachers":{"description":"How many different preachers taught it.","format":"int64","type":"integer"},"summary":{"description":"How the church has read the verse.","type":"string"},"teachings":{"description":"How many teachings the church has on this verse.","format":"int64","type":"integer"},"verse":{"description":"The verse, as a reference.","type":"string"},"verse_id":{"description":"The verse number within the Bible.","format":"int64","type":"integer"},"years":{"description":"How many years the church has taught it.","format":"int64","type":"integer"}},"required":["verse","verse_id","summary","teachings","preachers","years"],"type":"object"},"VerseTextWire":{"additionalProperties":false,"properties":{"n":{"description":"The verse number.","format":"int64","type":"integer"},"teachings":{"description":"How many teachings quote this verse.","format":"int64","type":"integer"},"text":{"description":"The text.","type":"string"}},"required":["n","text","teachings"],"type":"object"},"VerseUseWire":{"additionalProperties":false,"properties":{"in_answer":{"description":"Whether the verse appears in the answer.","type":"boolean"},"open_tensions":{"description":"How many unresolved differences between teachings the church has on the passage.","format":"int64","type":"integer"},"preachers":{"description":"How many different preachers taught it.","format":"int64","type":"integer"},"ref":{"description":"A scripture reference such as Romans 8:28.","type":"string"},"summary":{"description":"How the church has read the verse.","type":"string"},"teachings":{"description":"How many teachings the church has on this verse.","format":"int64","type":"integer"}},"required":["ref","teachings","preachers","open_tensions","in_answer"],"type":"object"},"WebhookChurchRef":{"additionalProperties":false,"properties":{"id":{"description":"The church id.","type":"string"},"name":{"description":"The church name.","type":"string"},"object":{"description":"Always church.","enum":["church"],"type":"string"},"slug":{"description":"The church web address.","type":"string"}},"required":["id","object","name","slug"],"type":"object"},"WebhookConversationRef":{"additionalProperties":false,"properties":{"id":{"description":"The conversation id.","type":"string"},"object":{"description":"Always conversation.","enum":["conversation"],"type":"string"},"surface":{"description":"Where it happened: staff, widget or share.","type":"string"}},"required":["id","object","surface"],"type":"object"},"WebhookEndpointStat":{"additionalProperties":false,"properties":{"delivered":{"description":"Whether your receiver answered 2xx.","format":"int64","type":"integer"},"failed":{"description":"How many deliveries failed.","format":"int64","type":"integer"},"last_delivery_at":{"description":"When the last delivery was attempted.","type":["string","null"]},"pending":{"description":"How many deliveries are waiting.","format":"int64","type":"integer"},"window_days":{"description":"The number of days the counts cover.","format":"int64","type":"integer"}},"type":"object"},"WebhookEndpointWire":{"additionalProperties":false,"properties":{"api_version":{"description":"The payload version this endpoint receives.","type":"string"},"child_scope":{"description":"Partner endpoints: none receives this church's own events, all also receives every customer church's events, selected only the churches in church_ids.","enum":["none","all","selected"],"type":"string"},"church_ids":{"description":"The customer churches this applies to.","items":{"type":"string"},"type":["array","null"]},"consecutive_failures":{"description":"Deliveries that failed in a row. At 20 the endpoint is disabled.","format":"int32","type":"integer"},"created_at":{"description":"When it was created, in RFC 3339 UTC.","type":"string"},"disabled_reason":{"description":"Why the endpoint was disabled, when it was.","type":"string"},"event_types":{"description":"The event types, or * for all.","items":{"type":"string"},"type":["array","null"]},"id":{"description":"The id, with a type prefix such as tch_ or note_.","type":"string"},"last_failure_at":{"description":"When a delivery last failed.","type":["string","null"]},"last_success_at":{"description":"When a delivery last succeeded.","type":["string","null"]},"mode":{"description":"live or test.","type":"string"},"name":{"description":"The name.","type":"string"},"object":{"description":"The object type.","type":"string"},"stats":{"$ref":"#/components/schemas/WebhookEndpointStat"},"status":{"description":"The current status.","type":"string"},"url":{"description":"The URL.","type":"string"}},"type":"object"},"WebhookEvent":{"additionalProperties":false,"description":"The JSON body Folio posts to your endpoint. The fields outside data are the same for every event; data.object is the full resource and its schema is on each event. The example on each event is the exact body, generated from the same catalogue the sender uses.","properties":{"actor":{"anyOf":[{"$ref":"#/components/schemas/WebhookUserIdRef"},{"type":"null"}],"description":"The team member who caused the event, null when a person did not (jobs, automations, Folio)."},"api_version":{"description":"The event schema version.","type":"string"},"church":{"$ref":"#/components/schemas/WebhookChurchRef","description":"The church the event is about. Sent to partner endpoints."},"created":{"description":"When the event happened.","format":"date-time","type":"string"},"data":{"additionalProperties":false,"description":"The event payload.","properties":{"object":{"additionalProperties":true,"description":"The full resource as it was when the event happened, in the same shape the REST API returns it.","type":"object"},"previous_attributes":{"additionalProperties":true,"description":"On update events, the earlier values of the fields that changed.","type":"object"}},"required":["object"],"type":"object"},"id":{"description":"The event id. The same on every retry and on every endpoint that receives the event; use it to deduplicate. The webhook-id header identifies one delivery.","type":"string"},"livemode":{"description":"False for sandbox churches, test keys and test events.","type":"boolean"},"object":{"description":"Always event.","enum":["event"],"type":"string"},"ordering_key":{"description":"A stable key per church; events with the same key are best processed in order.","type":"string"},"partner":{"additionalProperties":false,"description":"The partner that receives the event.","properties":{"id":{"description":"The partner church id.","type":"string"}},"required":["id"],"type":"object"},"request":{"anyOf":[{"additionalProperties":false,"properties":{"id":{"description":"The request id, the same value as the request_id in API responses.","type":"string"},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The Idempotency-Key the caller sent, if any."}},"required":["id","idempotency_key"],"type":"object"},{"type":"null"}],"description":"The API request that caused the event, null when Folio caused it."},"test":{"description":"True on events sent from the test button or the test endpoint.","type":"boolean"},"type":{"description":"The event type from the catalogue.","type":"string"}},"required":["id","object","api_version","created","type","livemode","request","actor","data"],"type":"object"},"WebhookEventTypeWire":{"additionalProperties":false,"properties":{"description":{"description":"A description.","type":"string"},"example":{"additionalProperties":{},"description":"The full body Folio would deliver for this event, nested.","type":"object"},"fields":{"description":"The top-level fields of data.object, for simple renderers. schema holds the full nested contract.","items":{"$ref":"#/components/schemas/WebhookFieldWire"},"type":["array","null"]},"group":{"description":"The group key.","type":"string"},"group_label":{"description":"The group's name.","type":"string"},"has_previous_attributes":{"description":"Whether updates of this event carry the earlier values of changed fields.","type":"boolean"},"object":{"description":"The object type.","type":"string"},"previous_attributes_fields":{"description":"The fields whose earlier values appear in previous_attributes.","items":{"type":"string"},"type":["array","null"]},"privacy_class":{"description":"What kind of data the event may carry.","enum":["content","metadata_only","account","financial"],"type":"string"},"privacy_note":{"description":"What the event carries that a receiver should treat with care.","type":"string"},"resource":{"description":"The value of data.object.object.","type":"string"},"schema":{"additionalProperties":{},"description":"JSON Schema 2020-12 of data.object. Shared object schemas are referenced as #/schemas/<name> and listed in the catalogue.","type":"object"},"source":{"description":"The part of Folio that sends the event.","type":"string"},"type":{"description":"The type.","type":"string"}},"type":"object"},"WebhookFieldWire":{"additionalProperties":false,"properties":{"description":{"description":"A description.","type":"string"},"name":{"description":"The name.","type":"string"},"required":{"description":"Whether the field is always present.","type":"boolean"},"type":{"description":"The type.","type":"string"}},"type":"object"},"WebhookInvoiceLine":{"additionalProperties":false,"description":"One line of an invoice.","properties":{"amount_minor":{"description":"The line amount before tax in the smallest currency unit.","type":"integer"},"description":{"description":"What was charged.","type":"string"}},"required":["description","amount_minor"],"type":"object"},"WebhookInvoiceRef":{"additionalProperties":false,"properties":{"id":{"description":"The invoice id.","type":"string"},"number":{"description":"The invoice number.","type":"string"},"object":{"description":"Always invoice.","enum":["invoice"],"type":"string"},"status":{"description":"The invoice status.","type":"string"}},"required":["id","object","number","status"],"type":"object"},"WebhookMoney":{"additionalProperties":false,"description":"An amount in the smallest currency unit with its currency.","properties":{"amount_minor":{"description":"The amount in the smallest currency unit, 7900 is 79.00.","type":"integer"},"currency":{"description":"The ISO 4217 currency code in upper case.","type":"string"}},"required":["amount_minor","currency"],"type":"object"},"WebhookNoteRef":{"additionalProperties":false,"properties":{"id":{"description":"The note id.","type":"string"},"object":{"description":"Always note.","enum":["note"],"type":"string"},"status":{"description":"The note status.","enum":["draft","in_review","approved","published","superseded","failed"],"type":"string"}},"required":["id","object","status"],"type":"object"},"WebhookPaymentMethodSummary":{"additionalProperties":false,"properties":{"brand":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The card brand, null when none is on file."},"exp_month":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The expiry month, null when unknown."},"exp_year":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"The expiry year, null when unknown."},"id":{"description":"The payment method id.","type":"string"},"kind":{"description":"card, bank or wallet.","type":"string"},"last4":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The last four digits, never the full number; null when none."},"object":{"description":"Always payment_method.","enum":["payment_method"],"type":"string"}},"required":["id","object","kind","brand","last4","exp_month","exp_year"],"type":"object"},"WebhookPlanRef":{"additionalProperties":false,"properties":{"id":{"description":"The plan id.","type":"string"},"key":{"description":"The plan key.","type":"string"},"name":{"description":"The plan name.","type":"string"},"object":{"description":"Always plan.","enum":["plan"],"type":"string"}},"required":["id","object","key","name"],"type":"object"},"WebhookProcessingStep":{"additionalProperties":false,"description":"One stage of processing a teaching.","properties":{"finished_at":{"description":"When the step finished.","format":"date-time","type":"string"},"key":{"description":"The step key.","type":"string"},"label":{"description":"The step name shown to the team.","type":"string"},"note":{"description":"A short plain note about the step.","type":"string"},"started_at":{"description":"When the step began.","format":"date-time","type":"string"},"state":{"description":"Where the step stands: pending, active, waiting, decision, done, skipped or failed.","type":"string"}},"required":["key","label","state","note"],"type":"object"},"WebhookSourceRef":{"additionalProperties":false,"properties":{"id":{"description":"The source id.","type":"string"},"kind":{"description":"upload, link, youtube, drive or live.","type":"string"},"name":{"description":"The source name.","type":"string"},"object":{"description":"Always source.","enum":["source"],"type":"string"}},"required":["id","object","name","kind"],"type":"object"},"WebhookSubscriptionRef":{"additionalProperties":false,"properties":{"id":{"description":"The subscription id.","type":"string"},"object":{"description":"Always subscription.","enum":["subscription"],"type":"string"},"status":{"description":"The subscription status.","type":"string"}},"required":["id","object","status"],"type":"object"},"WebhookTaxLine":{"additionalProperties":false,"description":"One tax charged on an invoice.","properties":{"amount_minor":{"description":"The tax amount in the smallest currency unit.","type":"integer"},"inclusive":{"description":"True when the price already included the tax.","type":"boolean"},"jurisdiction":{"description":"The tax jurisdiction, empty when not recorded.","type":"string"},"label":{"description":"What the tax is called on the invoice.","type":"string"},"rate_bps":{"description":"The rate in basis points, 2000 is 20 percent; 0 for reverse charge or zero-rated.","type":"integer"},"tax_type":{"description":"The kind of tax: vat, gst, sales_tax and so on, empty when the provider calculated it.","type":"string"},"treatment":{"description":"charge, reverse_charge, zero_rated or none.","type":"string"}},"required":["label","tax_type","rate_bps","treatment","inclusive","jurisdiction","amount_minor"],"type":"object"},"WebhookTeachingRef":{"additionalProperties":false,"properties":{"id":{"description":"The teaching id.","type":"string"},"name":{"description":"The teaching title, as every reference object names itself.","type":"string"},"object":{"description":"Always teaching.","enum":["teaching"],"type":"string"},"recorded_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"description":"When the teaching was recorded."},"speaker":{"description":"The speaker, empty when unknown.","type":"string"},"title":{"description":"The teaching title.","type":"string"}},"required":["id","object","name","title","speaker","recorded_at"],"type":"object"},"WebhookUserIdRef":{"additionalProperties":false,"properties":{"id":{"description":"The team member id.","type":"string"},"object":{"description":"Always user.","enum":["user"],"type":"string"}},"required":["id","object"],"type":"object"},"WidgetAskInputBody":{"additionalProperties":false,"properties":{"question":{"description":"The question, up to 1000 characters.","maxLength":1000,"minLength":1,"type":"string"},"session":{"description":"An anonymous visitor id you generate: 16 to 128 URL-safe characters.","pattern":"^[A-Za-z0-9_-]{16,128}$","type":"string"}},"type":"object"},"WidgetFeedbackInputBody":{"additionalProperties":false,"properties":{"kind":{"description":"The kind.","enum":["helpful","not_helpful"],"type":"string"}},"type":"object"},"WidgetHandoffInputBody":{"additionalProperties":false,"properties":{"email":{"description":"The email address.","format":"email","maxLength":320,"type":"string"},"kind":{"description":"The kind.","enum":["pastor","crisis_contact"],"type":"string"},"name":{"description":"The name.","maxLength":120,"type":"string"},"phone":{"description":"A phone number the church can call back.","maxLength":40,"type":"string"},"question":{"description":"The question, up to 1000 characters.","maxLength":1000,"type":"string"}},"type":"object"},"YearCountWire":{"additionalProperties":false,"properties":{"teachings":{"description":"How many teachings that year.","format":"int64","type":"integer"},"year":{"description":"The year.","format":"int64","type":"integer"}},"required":["year","teachings"],"type":"object"}},"securitySchemes":{"bearerAuth":{"bearerFormat":"folio_live_<prefix><secret> or folio_test_<prefix><secret>","description":"A church API key, created in the console under Developers. Send it as `Authorization: Bearer <key>`. The key chooses the church, so there is no church in the URL.\n\n`folio_live_` keys work against real churches only and `folio_test_` keys work against sandbox churches only; the check runs on every request.\n\nEach key carries scopes such as `notes:read`. The scope an operation needs is shown on the operation. Wildcards: `machine:read` grants every read scope and `machine:*` grants every church scope. Give a key only what it needs.\n\nThe full secret is shown once, when the key is created. Folio stores only a hash.","scheme":"bearer","type":"http"},"deviceKey":{"bearerFormat":"folio_booth_<prefix><secret>","description":"A booth device key, returned once by POST /v1/devices/pair. Every call also sends `X-Folio-Device-Contract`. A revoked key gets 401 on its next call.","scheme":"bearer","type":"http"},"partnerKey":{"bearerFormat":"folio_live_<prefix><secret>","description":"A partner key, created in a partner church under Developers, Partners. It manages customer churches (`partners:read`, `partners:write`) and can call any church route as one of them by sending `X-Folio-Church`. The wildcard `*` grants everything, including partner routes; it exists only on partner keys.","scheme":"bearer","type":"http"}}}}