{"openapi":"3.1.0","info":{"title":"FaithFinance API","version":"1.0.0","description":"What each member declared was in their envelope, and the treasurer's count, for your\naccounting system. We are a pass-through: you keep the books.\n\n**Envelopes are reusable.** An envelope identifies the slip, not the giver. Each use is a\n*giving*: who gave, the breakdown, the expected total, the count and the receipt. An envelope\ncarries one uncounted giving at a time and is free again once it is counted. A member may\ndeclare before they hold an envelope (`pending`); the giving is attached when the envelope\nis scanned.\n\n**Authentication.** Every call (except this document) sends an app key made in the console:\n`Authorization: Api-Key wb_…` (or `X-Api-Key`). Never `Bearer`. A key belongs to one church\nand carries scopes; the church is always the key's.\n\n**Amounts** are integers in the church's minor unit (cents): KES 1,500.00 is `150000`.\n\n**Lists** take `limit` and `cursor` and return `next` (null on the last page).\n\n**Retries.** Send `Idempotency-Key: <your id>` on a POST and a repeat within 24 hours gets the\nfirst answer (with `Idempotent-Replayed: true`) instead of doing it twice.\n\n**Webhooks.** Each event is POSTed as JSON (the `Event` schema) with\n`FaithFinance-Event`, `FaithFinance-Delivery` and\n`FaithFinance-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, \"<t>.<raw body>\")>`.\nCheck the MAC on the raw bytes, and refuse a `t` more than 5 minutes off. Answer 2xx within\n10 seconds. Anything else is retried after 1m, 5m, 30m, 2h, 6h, 12h and 24h. A delivery can\narrive more than once, so key on the event `id`. Events: `giving.declared`, `giving.changed`, `giving.attached`, `giving.cancelled`, `giving.verified`, `giving.discrepancy`, `giving.payment`, `batch.closed`, `webhook.ping`.\n`GET /events` returns the same events for polling.\n\n**Scopes:** `church:read`, `categories:read`, `categories:write`, `envelopes:read`, `envelopes:write`, `givings:read`, `givings:write`, `verifications:write`, `batches:read`, `batches:write`, `events:read`, `webhooks:read`, `webhooks:write`.\n"},"servers":[{"url":"https://faithfinance.adventhymnals.org/api/plugins/offerscan/v1"}],"paths":{"/church":{"get":{"summary":"The church this key belongs to","description":"Scope: `church:read`.","security":[{"ApiKey":["church:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Church"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/categories":{"get":{"summary":"The lines an envelope can have","description":"Scope: `categories:read`.","security":[{"ApiKey":["categories:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"next":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"summary":"Add a category, or change one by code","description":"Scope: `categories:write`.","security":[{"ApiKey":["categories:write"]}],"responses":{"200":{"description":"Changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}}},"201":{"description":"Added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryInput"}}}}}},"/envelopes":{"get":{"summary":"Envelopes, by serial","description":"Scope: `envelopes:read`.","security":[{"ApiKey":["envelopes:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Envelope"}},"next":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"status","in":"query","schema":{"enum":["blank","declared","verified","void"]}},{"name":"run","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"The `next` of the previous page."}]}},"/envelopes/runs":{"post":{"summary":"Make envelopes to print","description":"Each envelope comes with its `token`; print its QR as `https://<site>/e/<token>` and its `display_code` under it.\n\nScope: `envelopes:write`.","security":[{"ApiKey":["envelopes:write"]}],"responses":{"201":{"description":"Made","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","minimum":1,"maximum":2000},"label":{"type":"string"}}}}}}}},"/envelopes/{code}":{"get":{"summary":"One envelope: whether it is free, and the giving it carries","description":"Scope: `envelopes:read`.","security":[{"ApiKey":["envelopes:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"The envelope code (`K7P2QX9M3TZA`, dashes allowed) or the full signed token from its QR."}]}},"/givings":{"get":{"summary":"Givings, newest first","description":"Scope: `givings:read`.","security":[{"ApiKey":["givings:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Giving"}},"next":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"status","in":"query","schema":{"enum":["pending","declared","verified","cancelled"]}},{"name":"batch","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"The `next` of the previous page."}]},"post":{"summary":"Declare a giving","description":"In an envelope (it must be free: 409 `envelope_in_use` otherwise), or `pending` without one.\n\nScope: `givings:write`.","security":[{"ApiKey":["givings:write"]}],"responses":{"201":{"description":"Declared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Giving"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingInput"}}}}}},"/givings/{id}":{"get":{"summary":"One giving","description":"Scope: `givings:read`.","security":[{"ApiKey":["givings:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Giving"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"put":{"summary":"Change a giving until it is counted","description":"Scope: `givings:write`.","security":[{"ApiKey":["givings:write"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Giving"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GivingInput"}}}}}},"/givings/{id}/attach":{"post":{"summary":"Put a pending giving into an envelope","description":"Scope: `givings:write`.","security":[{"ApiKey":["givings:write"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Giving"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["envelope"],"properties":{"envelope":{"type":"string"}}}}}}}},"/givings/{id}/cancel":{"post":{"summary":"Withdraw a giving that was not counted (its envelope is free again)","description":"Scope: `givings:write`.","security":[{"ApiKey":["givings:write"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Giving"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/givings/{id}/verification":{"get":{"summary":"The count","description":"Scope: `givings:read`.","security":[{"ApiKey":["givings:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"post":{"summary":"Record the count","description":"`result` is `matched` when the count equals the declared total, otherwise `discrepancy` (and a `giving.discrepancy` event). The envelope is then free for its next use.\n\nScope: `verifications:write`.","security":[{"ApiKey":["verifications:write"]}],"responses":{"201":{"description":"Counted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationInput"}}}}}},"/batches":{"get":{"summary":"Batches, newest first","description":"Scope: `batches:read`.","security":[{"ApiKey":["batches:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Batch"}},"next":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"status","in":"query","schema":{"enum":["open","closed"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"The `next` of the previous page."}]},"post":{"summary":"Open a batch","description":"Scope: `batches:write`.","security":[{"ApiKey":["batches:write"]}],"responses":{"201":{"description":"Opened","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","format":"date"},"label":{"type":"string"}}}}}}}},"/batches/{id}":{"get":{"summary":"A batch: totals by category and every giving counted in it","description":"Scope: `batches:read`.","security":[{"ApiKey":["batches:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/batches/{id}/close":{"post":{"summary":"Close a batch","description":"Scope: `batches:write`.","security":[{"ApiKey":["batches:write"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/events":{"get":{"summary":"Events in order, for polling","description":"`next` is always set: poll again with it to get only what is new.\n\nScope: `events:read`.","security":[{"ApiKey":["events:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"next":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"type","in":"query","schema":{"enum":["giving.declared","giving.changed","giving.attached","giving.cancelled","giving.verified","giving.discrepancy","giving.payment","batch.closed","webhook.ping"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"The `next` of the previous page."}]}},"/webhooks":{"get":{"summary":"Webhook endpoints","description":"Scope: `webhooks:read`.","security":[{"ApiKey":["webhooks:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"next":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"summary":"Register an endpoint","description":"Scope: `webhooks:write`.","security":[{"ApiKey":["webhooks:write"]}],"responses":{"201":{"description":"Registered; the secret is shown only now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookInput"}}}}}},"/webhooks/{id}":{"get":{"summary":"An endpoint and its last 50 deliveries","description":"Scope: `webhooks:read`.","security":[{"ApiKey":["webhooks:read"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"delete":{"summary":"Remove an endpoint","description":"Scope: `webhooks:write`.","security":[{"ApiKey":["webhooks:write"]}],"responses":{"204":{"description":"Removed"},"400":{"$ref":"#/components/responses/Invalid"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}}},"webhooks":{"giving.declared":{"post":{"summary":"giving.declared","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"giving.changed":{"post":{"summary":"giving.changed","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"giving.attached":{"post":{"summary":"giving.attached","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"giving.cancelled":{"post":{"summary":"giving.cancelled","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"giving.verified":{"post":{"summary":"giving.verified","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"giving.discrepancy":{"post":{"summary":"giving.discrepancy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"giving.payment":{"post":{"summary":"giving.payment","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"batch.closed":{"post":{"summary":"batch.closed","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}},"webhook.ping":{"post":{"summary":"webhook.ping","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Any 2xx acknowledges it"}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"Authorization","description":"The value is `Api-Key wb_…`."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":200}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","examples":["invalid","not_found","already_verified","total_mismatch"]},"message":{"type":"string"},"fields":{"type":"object","additionalProperties":{"type":"string"}}}}}},"Church":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"currency":{"type":"string","description":"ISO 4217"},"pay":{"type":"object","description":"The M-Pesa ways it takes: stk, paybill, till, send_money → {number?, name?, auto}. `auto`: confirmed without the treasurer."}}},"Category":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"order":{"type":"integer"},"active":{"type":"boolean"},"description":{"type":"string","description":"What an appeal is for."},"goal":{"type":["integer","null"],"minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"raised":{"type":"integer","minimum":0,"description":"Counted or paid so far (with a goal)."},"ends_on":{"type":["string","null"],"format":"date","description":"The last day it is offered to members."}}},"CategoryInput":{"type":"object","required":["code"],"properties":{"code":{"type":"string","pattern":"^[a-z0-9_-]{1,40}$"},"name":{"type":"string"},"order":{"type":"integer"},"active":{"type":"boolean"},"description":{"type":"string","maxLength":300},"goal":{"type":["integer","null"],"minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"ends_on":{"type":["string","null"],"format":"date"}}},"Payment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"method":{"enum":["stk","paybill","till","send_money"]},"amount":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"status":{"enum":["pending","confirmed","rejected","failed"]},"receipt":{"type":"string","description":"The M-Pesa code"},"phone":{"type":"string","description":"Masked"},"note":{"type":"string"},"at":{"type":"string","format":"date-time"}}},"GivingPayment":{"type":["object","null"],"description":"A giving paid by M-Pesa rather than in an envelope.","properties":{"method":{"type":["string","null"]},"paid":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"due":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"prompting":{"type":"boolean","description":"An M-Pesa prompt is on the member's phone."},"checking":{"type":"boolean","description":"A payment the member reported is being confirmed."},"options":{"type":"object"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/Payment"}}}},"Line":{"type":"object","required":["category","amount"],"properties":{"category":{"type":"string","description":"A category code"},"name":{"type":"string","readOnly":true},"amount":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."}}},"EnvelopeRef":{"type":["object","null"],"properties":{"code":{"type":"string"},"display_code":{"type":"string"},"serial":{"type":"integer"}}},"Giving":{"type":"object","description":"One use of an envelope: who gave, what they declared, and the count.","properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string","description":"The giving code the member shows to have it attached to an envelope; also the receipt number."},"status":{"enum":["pending","declared","verified","cancelled"],"description":"`pending`: declared, no envelope yet. `declared`: in an envelope, waiting to be counted."},"envelope":{"$ref":"#/components/schemas/EnvelopeRef"},"giver_name":{"type":"string"},"giver_ref":{"type":"string"},"receipt_email":{"type":"string"},"receipt_phone":{"type":"string"},"total":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"source":{"enum":["member","treasurer","api"]},"lines":{"type":"array","items":{"$ref":"#/components/schemas/Line"}},"declared_at":{"type":"string","format":"date-time"},"attached_at":{"type":["string","null"],"format":"date-time"},"verification":{"oneOf":[{"$ref":"#/components/schemas/Verification"},{"type":"null"}],"description":"For a giving paid by M-Pesa: once payments cover it (no batch)."},"pay_method":{"type":["string","null"],"enum":["stk","paybill","till","send_money",null]},"payment":{"$ref":"#/components/schemas/GivingPayment"}}},"GivingInput":{"type":"object","required":["lines"],"properties":{"envelope":{"type":"string","description":"Envelope code or token. Omit to declare before there is an envelope (`pending`)."},"lines":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/Line"}},"total":{"type":"integer","minimum":0,"description":"Optional: when given, it must equal the sum of the lines."},"giver_name":{"type":"string","maxLength":160},"giver_ref":{"type":"string","maxLength":60},"receipt_email":{"type":"string","format":"email"},"receipt_phone":{"type":"string"}}},"Verification":{"type":"object","properties":{"batch":{"type":["string","null"],"format":"uuid","description":"null when M-Pesa payments covered it"},"declared_total":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"counted_total":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"difference":{"type":"integer","description":"counted minus declared"},"result":{"enum":["matched","discrepancy"]},"note":{"type":"string"},"verified_by":{"type":["string","null"]},"verified_at":{"type":"string","format":"date-time"}}},"VerificationInput":{"type":"object","required":["batch","counted_total"],"properties":{"batch":{"type":"string","format":"uuid"},"counted_total":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"note":{"type":"string","maxLength":500}}},"Envelope":{"type":"object","description":"A reusable slip. It identifies the envelope, never the giver.","properties":{"code":{"type":"string"},"display_code":{"type":"string","examples":["K7P2-QX9M-3TZA"]},"serial":{"type":"integer"},"active":{"type":"boolean"},"token":{"type":"string","description":"What its QR carries (after /e/). Lists only."},"free":{"type":"boolean","description":"Carries no uncounted giving. One envelope only."},"uses":{"type":"integer","description":"Givings counted in it so far. One envelope only."},"giving":{"oneOf":[{"$ref":"#/components/schemas/Giving"},{"type":"null"}],"description":"The giving it carries now. One envelope only."}}},"Run":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"count":{"type":"integer"},"first_serial":{"type":"integer"},"envelopes":{"type":"array","items":{"$ref":"#/components/schemas/Envelope"}}}},"BatchTotals":{"type":"object","properties":{"envelopes":{"type":"integer"},"declared":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"counted":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."},"difference":{"type":"integer"},"discrepancies":{"type":"integer"},"by_category":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"amount":{"type":"integer","minimum":0,"description":"In the church's minor unit: KES 1,500.00 is 150000."}}}}}},"Batch":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"date":{"type":"string","format":"date"},"label":{"type":"string"},"status":{"enum":["open","closed"]},"closed_at":{"type":["string","null"],"format":"date-time"},"totals":{"$ref":"#/components/schemas/BatchTotals"},"givings":{"type":"array","items":{"$ref":"#/components/schemas/Giving"}}}},"Event":{"type":"object","description":"Exactly the body a webhook receives.","properties":{"id":{"type":"string","examples":["evt_3f…"]},"type":{"enum":["giving.declared","giving.changed","giving.attached","giving.cancelled","giving.verified","giving.discrepancy","giving.payment","batch.closed","webhook.ping"]},"created":{"type":"string","format":"date-time"},"church":{"$ref":"#/components/schemas/Church"},"data":{"type":"object"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"description":{"type":"string"},"events":{"type":"array","items":{"enum":["giving.declared","giving.changed","giving.attached","giving.cancelled","giving.verified","giving.discrepancy","giving.payment","batch.closed","webhook.ping"]},"description":"Empty: every event."},"active":{"type":"boolean"},"secret":{"type":"string","description":"Only in the answer that creates it."},"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/Delivery"}}}},"WebhookInput":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"https, public address"},"events":{"type":"array","items":{"enum":["giving.declared","giving.changed","giving.attached","giving.cancelled","giving.verified","giving.discrepancy","giving.payment","batch.closed","webhook.ping"]}},"description":{"type":"string"}}},"Delivery":{"type":"object","properties":{"id":{"type":"string"},"event":{"type":"string"},"type":{"type":"string"},"status":{"enum":["pending","delivered","failed","dead"]},"attempts":{"type":"integer"},"last_status_code":{"type":["integer","null"]},"last_error":{"type":"string"},"next_attempt_at":{"type":["string","null"],"format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"}}}},"responses":{"Invalid":{"description":"The request is not right; `fields` says where","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthenticated":{"description":"No key, or not a live one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks the scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not this church’s, or does not exist","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"Not now: already counted, batch closed, …","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}