{"openapi":"3.1.0","info":{"title":"Masjid Fikra Public API","version":"1.0.0","description":"Server-to-server REST API for masjids on Masjid Fikra. Use a secret API key minted in the portal under Settings → Developer to read your masjid data and start checkout sessions on your masjid's connected Stripe account.","contact":{"name":"Masjid Fikra","url":"https://masjidfikra.com","email":"support@masjidfikra.com"}},"servers":[{"url":"https://api.masjidfikra.com/v1","description":"Production"},{"url":"https://api-dev.masjidfikra.com/v1","description":"Dev"}],"tags":[{"name":"masjid","description":"Masjid identity + contact info."},{"name":"donation_types","description":"Configured donation buckets."},{"name":"membership_tiers","description":"Public membership tiers."},{"name":"donations","description":"Donation records (PII included)."},{"name":"members","description":"Member roster (PII included)."},{"name":"forms","description":"Form definitions and submissions."},{"name":"events","description":"Calendar events."},{"name":"checkout","description":"Stripe Checkout session creation."},{"name":"prayer_times","description":"Adhan + iqamah times for masjid-tech integrators."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"mfk_sec_*","description":"Secret API key. Format: `mfk_sec_live_<43chars>` (or `mfk_sec_test_*` once test mode lands). Pass as `Authorization: Bearer <key>`."}},"schemas":{"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"details":{}}},"Masjid":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"legalName":{"type":["string","null"]},"ein":{"type":["string","null"]},"about":{"type":["string","null"]},"website":{"type":["string","null"]},"phone":{"type":["string","null"]},"email":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"heroUrl":{"type":["string","null"]},"address":{"type":"object","properties":{"line1":{"type":["string","null"]},"line2":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zip":{"type":["string","null"]}}},"acceptsOnlineDonations":{"type":"boolean"}}},"DonationType":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"amountMode":{"type":"string","enum":["any","fixed","suggested"]},"fixedAmountCents":{"type":["integer","null"]},"suggestedAmountsCents":{"type":"array","items":{"type":"integer"}},"minAmountCents":{"type":"integer"},"isRecurring":{"type":"boolean"},"recurringInterval":{"type":["string","null"],"enum":["month","year",null]},"isZakat":{"type":"boolean"},"sortOrder":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"MembershipTier":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"amountCents":{"type":"integer"},"period":{"type":"string"},"interval":{"type":["string","null"]},"isPopular":{"type":"boolean"},"sortOrder":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Donation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"amountCents":{"type":"integer"},"currency":{"type":"string"},"method":{"type":"string"},"status":{"type":"string","enum":["active","voided"]},"donorName":{"type":["string","null"]},"donorEmail":{"type":["string","null"]},"fundId":{"type":["string","null"],"format":"uuid"},"fundName":{"type":["string","null"]},"donationTypeId":{"type":["string","null"],"format":"uuid"},"donationTypeName":{"type":["string","null"]},"receivedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"stripeSessionId":{"type":["string","null"]},"stripePaymentIntentId":{"type":["string","null"]},"stripeChargeId":{"type":["string","null"]}}},"Member":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"fullName":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"joinedAt":{"type":"string","format":"date"},"isArchived":{"type":"boolean"},"isActive":{"type":"boolean"},"currentTierId":{"type":["string","null"],"format":"uuid"},"currentTierName":{"type":["string","null"]},"nextRenewalDate":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"FormDefinition":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"fields":{},"requirementsList":{"type":"array","items":{"type":"string"}},"requireAgreement":{"type":"boolean"},"agreementLabel":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"FormSubmission":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"formType":{"type":"string"},"status":{"type":"string"},"fields":{},"submittedByName":{"type":["string","null"]},"submittedByEmail":{"type":["string","null"]},"submittedByPhone":{"type":["string","null"]},"submittedAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Event":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":["string","null"]},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":["string","null"],"format":"date-time"},"location":{"type":["string","null"]},"audience":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"PrayerTimesDay":{"type":"object","required":["date","adhan","iqama","jumuah","source"],"properties":{"date":{"type":"string","format":"date","description":"YYYY-MM-DD in masjid timezone."},"adhan":{"type":["object","null"],"description":"First-call (adhan) times in `HH:MM` 24h, masjid-local timezone. Null if a manual-mode masjid has no override stored for this date.","properties":{"fajr":{"type":"string"},"sunrise":{"type":"string"},"dhuhr":{"type":"string"},"asr":{"type":"string"},"maghrib":{"type":"string"},"isha":{"type":"string"}}},"iqama":{"type":"object","description":"Second-call (iqamah) times. Schema today stores a single weekday set, returned identically on every day in the range. Null per prayer if the masjid has not set one.","properties":{"fajr":{"type":["string","null"]},"dhuhr":{"type":["string","null"]},"asr":{"type":["string","null"]},"maghrib":{"type":["string","null"]},"isha":{"type":["string","null"]}}},"jumuah":{"type":"array","description":"Jumu’ah service slots — empty array on non-Fridays.","items":{"type":"object","properties":{"time":{"type":"string"},"label":{"type":["string","null"]},"khateeb":{"type":["string","null"]},"language":{"type":["string","null"]}}}},"source":{"type":"string","enum":["computed","override","manual"],"description":"`computed` = derived from method+coords. `override` = at least one prayer overridden by a per-day entry on top of the computation. `manual` = masjid uses method=manual and the row came entirely from per-day stored values."}}},"PrayerTimesResponse":{"type":"object","required":["masjid","config","days"],"properties":{"masjid":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"timezone":{"type":"string"}}},"config":{"type":"object","properties":{"method":{"type":"string","enum":["ISNA","MWL","Egyptian","UmmAlQura","Karachi","Tehran","manual"]},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]}}},"days":{"type":"array","items":{"$ref":"#/components/schemas/PrayerTimesDay"}}}},"CheckoutSession":{"type":"object","properties":{"checkoutUrl":{"type":"string","format":"uri"},"sessionId":{"type":"string"},"expiresAt":{"type":["string","null"],"format":"date-time"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"API key is missing the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"BadRequest":{"description":"Request validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooManyRequests":{"description":"Per-key rate limit exceeded (100 req/sec).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/masjid":{"get":{"tags":["masjid"],"summary":"Get the masjid profile","security":[{"bearerAuth":["read:masjid"]}],"responses":{"200":{"description":"Masjid profile.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Masjid"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/donation-types":{"get":{"tags":["donation_types"],"summary":"List donation types","security":[{"bearerAuth":["read:donation_types"]}],"responses":{"200":{"description":"Active donation types.","content":{"application/json":{"schema":{"type":"object","required":["data","hasMore","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DonationType"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"],"format":"uuid"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/membership-tiers":{"get":{"tags":["membership_tiers"],"summary":"List membership tiers","security":[{"bearerAuth":["read:membership_tiers"]}],"responses":{"200":{"description":"Public membership tiers.","content":{"application/json":{"schema":{"type":"object","required":["data","hasMore","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MembershipTier"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"],"format":"uuid"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/donations":{"get":{"tags":["donations"],"summary":"List donations","security":[{"bearerAuth":["read:donations"]}],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"starting_after","schema":{"type":"string","format":"uuid"},"description":"Cursor returned as `nextCursor` from a prior page."},{"in":"query","name":"from","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"to","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"status","schema":{"type":"string","enum":["active","voided"]}}],"responses":{"200":{"description":"Donation page.","content":{"application/json":{"schema":{"type":"object","required":["data","hasMore","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Donation"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"],"format":"uuid"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/donations/{id}":{"get":{"tags":["donations"],"summary":"Get a donation","security":[{"bearerAuth":["read:donations"]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Donation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Donation"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/members":{"get":{"tags":["members"],"summary":"List members","security":[{"bearerAuth":["read:members"]}],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"starting_after","schema":{"type":"string","format":"uuid"},"description":"Cursor returned as `nextCursor` from a prior page."}],"responses":{"200":{"description":"Member page.","content":{"application/json":{"schema":{"type":"object","required":["data","hasMore","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Member"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"],"format":"uuid"}}}}}}}}},"/members/{id}":{"get":{"tags":["members"],"summary":"Get a member","security":[{"bearerAuth":["read:members"]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Member with recent payment history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}}}}},"/forms":{"get":{"tags":["forms"],"summary":"List form definitions","security":[{"bearerAuth":["read:forms"]}],"responses":{"200":{"description":"Form definitions.","content":{"application/json":{"schema":{"type":"object","required":["data","hasMore","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FormDefinition"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"],"format":"uuid"}}}}}}}}},"/forms/{type}/submissions":{"get":{"tags":["forms"],"summary":"List submissions for a form type","security":[{"bearerAuth":["read:forms"]}],"parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"starting_after","schema":{"type":"string","format":"uuid"},"description":"Cursor returned as `nextCursor` from a prior page."}],"responses":{"200":{"description":"Submission page.","content":{"application/json":{"schema":{"type":"object","required":["data","hasMore","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FormSubmission"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"],"format":"uuid"}}}}}}}}},"/forms/{type}":{"post":{"tags":["forms"],"summary":"Submit a form","security":[{"bearerAuth":["write:forms"]}],"parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["payload"],"properties":{"payload":{"type":"object"},"agreementAccepted":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Submission accepted.","content":{"application/json":{"schema":{"type":"object","properties":{"submissionId":{"type":"string","format":"uuid"},"submittedAt":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/events":{"get":{"tags":["events"],"summary":"List upcoming events","security":[{"bearerAuth":["read:events"]}],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"starting_after","schema":{"type":"string","format":"uuid"},"description":"Cursor returned as `nextCursor` from a prior page."}],"responses":{"200":{"description":"Event page.","content":{"application/json":{"schema":{"type":"object","required":["data","hasMore","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"],"format":"uuid"}}}}}}}}},"/checkout/donation":{"post":{"tags":["checkout"],"summary":"Create a donation checkout session","security":[{"bearerAuth":["write:checkout"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["donationTypeId"],"properties":{"donationTypeId":{"type":"string","format":"uuid"},"amountCents":{"type":"integer","minimum":100},"coverFees":{"type":"boolean"},"donorEmail":{"type":"string","format":"email"},"donorName":{"type":"string"},"anonymous":{"type":"boolean"},"successUrl":{"type":"string","format":"uri","description":"Optional. Must exactly match a redirectUri registered on this API key."},"cancelUrl":{"type":"string","format":"uri","description":"Optional. Must exactly match a redirectUri registered on this API key."}}}}}},"responses":{"201":{"description":"Checkout session created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/checkout/membership":{"post":{"tags":["checkout"],"summary":"Create a membership checkout session","security":[{"bearerAuth":["write:checkout"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tierId","applicant"],"properties":{"tierId":{"type":"string","format":"uuid"},"applicant":{"type":"object","required":["fullName","email"],"properties":{"fullName":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"addressLine1":{"type":"string"},"addressLine2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"}}},"successUrl":{"type":"string","format":"uri"},"cancelUrl":{"type":"string","format":"uri"}}}}}},"responses":{"201":{"description":"Checkout session created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/masjids/{slug}/prayer-times":{"get":{"tags":["prayer_times"],"summary":"Get adhan + iqamah times for a date range","description":"Returns up to 90 days of prayer times for the masjid identified by `slug`. The slug must match the masjid that minted the API key. Times are emitted as `HH:MM` 24h strings in the masjid’s local timezone — never UTC. Per-day `manualOverrides` win over the calculation; `source` discriminates so integrators can tell whether they’re seeing a published adjustment or a raw calc.","security":[{"bearerAuth":["prayer.read"]}],"parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}},{"in":"query","name":"date","schema":{"type":"string","format":"date"},"description":"Start date (inclusive). Defaults to today in masjid timezone."},{"in":"query","name":"end","schema":{"type":"string","format":"date"},"description":"End date (inclusive). Range capped at 90 days from `date`. Defaults to `date`."}],"responses":{"200":{"description":"Prayer times for the requested range.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrayerTimesResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Masjid not found, slug does not match the API key’s tenant, or the masjid has not configured a calculation method + coordinates (`PRAYER_TIMES_NOT_CONFIGURED`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/masjids/{slug}/prayer-times/today":{"get":{"tags":["prayer_times"],"summary":"Get today’s prayer times","description":"Convenience form of `/masjids/{slug}/prayer-times` fixed to today in the masjid’s timezone.","security":[{"bearerAuth":["prayer.read"]}],"parameters":[{"in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Prayer times for today.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrayerTimesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Masjid not found or not configured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"security":[{"bearerAuth":[]}]}