thefaithapp_giving 0.2.1
thefaithapp_giving: ^0.2.1 copied to clipboard
Authenticated, provider-extensible giving views for TheFaithApp Flutter applications.
TheFaithApp Giving for Flutter #
thefaithapp_giving renders authenticated general-giving and campaign-giving
flows backed by TheFaithApp. It includes the amount, fund, currency, recurring,
fee-covering, and memo UI, then presents the church's configured default
payment method.
The package currently includes handlers for:
- Stripe PaymentSheet
- PayPal hosted checkout
- Flutterwave hosted checkout
The shared checkout engine and GivingPaymentHandler interface allow another
payment method to be added without duplicating the general and campaign forms.
Install #
dependencies:
thefaithapp_auth: ^0.1.0
thefaithapp_giving: ^0.2.1
Follow the native setup required by flutter_stripe and
webview_flutter for the platforms your application supports.
For Android, the host app needs the Internet permission in its main manifest,
FlutterFragmentActivity for MainActivity, and an AppCompat-compatible launch
and normal theme (for example Theme.MaterialComponents.DayNight.NoActionBar).
Follow Flutter Stripe's Android and release setup,
including its ProGuard configuration, then perform a full native rebuild.
These host requirements also apply when using the giving package's built-in
PaymentSheet handler. Use HTTPS for API and hosted checkout traffic.
If Stripe 13.x cannot resolve the optional play-services-tapandpay dependency
and your host app does not use Stripe Issuing, exclude that restricted optional
artifact in android/build.gradle.kts:
subprojects {
configurations.configureEach {
exclude(group = "com.google.android.gms", module = "play-services-tapandpay")
}
}
Keep Stripe's release ProGuard rules. Apps that use card issuing should follow Stripe's issuing access and setup requirements instead of this exclusion.
Authenticate first #
Giving requires a valid member session from thefaithapp_auth:
final auth = TheFaithAppAuth(apiKey: 'your-client-key');
await auth.signIn();
final giving = TheFaithAppGiving(auth: auth);
The giving package never accepts or sends a member_id or client_id. It uses
the auth package's origin-restricted authorized client. The API resolves the
member and church from the bearer token and client key, then scopes every fund,
campaign, checkout, capture, verification, and status request to that identity.
Handle access failures #
The error categories and fields below apply to 0.2.0. For the migration from 0.1.0, see Upgrading from 0.1.0.
A valid sign-in does not guarantee that the church's plan includes SDK access.
Handle GivingException.code according to the failure:
| Code | Meaning | Next step |
|---|---|---|
GivingErrorCode.notAuthenticated |
No usable member session, or HTTP 401 | Follow your app's sign-in recovery path. |
GivingErrorCode.planAccessDenied |
HTTP 403 with a recognized plan denial | Ask the church administrator to review plan access. Signing in again does not change the plan. |
GivingErrorCode.forbidden |
Another HTTP 403 permission denial | Check the permitted resource/action with the church; do not assume the member needs to sign in again. |
statusCode retains the HTTP status. serverErrorCode retains a valid bounded
machine code, including plan_product_unavailable or
plan_entitlement_required. For those plan denials, optional planAccess
contains only typed identifiers: type, product or entitlement,
currentPlan, and recommendedPlan. Missing or malformed context is omitted;
it does not prevent recognizing a plan denial. No raw response or credentials
are retained in these fields.
When updating to this change, add the new cases to exhaustive
GivingErrorCode switches. The built-in view reports the error through
onError and displays its message; it does not sign the member out.
Upgrading from 0.1.0 #
Update the giving constraint to ^0.2.1; the auth dependency stays on
^0.1.0. A decoded API error with HTTP 403 was previously reported as notAuthenticated. In 0.2.0,
recognized plan denials are planAccessDenied and other decoded HTTP 403 errors are
forbidden. Add both cases to exhaustive switches, and keep sign-in recovery
for missing sessions and HTTP 401.
void handleGivingError(GivingException error) {
switch (error.code) {
case GivingErrorCode.notAuthenticated:
// Offer the app's sign-in recovery path.
break;
case GivingErrorCode.planAccessDenied:
// Ask the church administrator to review plan access.
break;
case GivingErrorCode.forbidden:
// Check permission for this resource or action.
break;
default:
// Keep handling the other giving errors.
break;
}
}
The new serverErrorCode and planAccess fields are optional.
GivingCheckoutSession.paypalSubscriptionId is also nullable and is populated
when the checkout response supplies a PayPal subscription ID.
General giving #
GivingView.general(
giving: giving,
onCompleted: (result) {
if (result.isSuccessful) {
// The platform has confirmed the provider payment.
}
},
)
For giving launched from a prayer room, pass prayerRoomId. The platform
validates that the room belongs to the signed-in member's church and permits
giving.
Campaign giving #
GivingView.campaign(
giving: giving,
campaignId: 42,
onCompleted: (result) {
// Handle succeeded, pending, cancelled, or failed state.
},
)
If the campaign has additional donor fields, the built-in view renders them,
validates required values, and includes the responses in the authenticated
checkout. Text, multiline text, number, email, telephone, select, radio,
checkbox, and date fields are supported. Headless/custom UIs can submit the
same data through CampaignGivingRequest.formFields.
Both views intentionally use the church's active/default method. Payment methods have different account, currency, recurrence, and presentation rules, so the platform owns method selection and configuration.
The built-in forms show recurring choices only when the API configuration explicitly enables recurring giving. Otherwise, they submit one-time gifts.
Manage recurring gifts #
Recurring general and campaign gifts use the same authenticated SDK:
final subscriptions = await giving.getSubscriptions();
final gift = subscriptions.first;
await giving.cancelSubscription(gift);
Each GivingSubscription includes its general or campaign target, so numeric
IDs from the two donation tables can never be confused. Cancellation is
rechecked against the signed-in member, church, and campaign by the platform.
Add a payment method #
Register a handler whose provider matches the value returned by the giving
configuration endpoint:
final giving = TheFaithAppGiving(
auth: auth,
paymentHandlers: [MyPaymentHandler()],
);
A handler receives a checkout-scoped GivingCheckoutContext. It can present
native UI or a hosted flow, then ask the platform for authoritative status.
It does not receive the member ID, client ID, bearer token, or API key. Never
log or persist checkout secrets from GivingCheckoutSession. New handlers can
read provider-specific response fields from session.providerData while the
shared typed fields remain stable. A handler must return the provider and
donation ID from its checkout session; the SDK rejects mismatched results and
reports the real checkout as abandoned.
Payment security #
- The platform creates amounts, destinations, references, and provider sessions after validating church-owned funds and campaigns.
- Checkout status is scoped to the authenticated member and church.
- Returning from PaymentSheet or a WebView is not treated as proof of payment.
- One-time Stripe gifts do not request future-use consent or save the payment method for off-session charges. Recurring gifts explicitly request it.
- If a failed Stripe attempt is followed by closing PaymentSheet, the SDK preserves the webhook-authoritative failed result instead of reporting a misleading cancellation.
- Closing a payment view reports the checkout as abandoned. The platform keeps a short webhook grace period, then cancels it; silent app terminations are covered by the checkout's server-side expiry.
- Hosted callbacks require HTTPS in production, the exact TheFaithApp API origin, the exact callback path, and the matching donation ID. Plain HTTP is accepted only for exact loopback origins during local development.
- The backend verifies stored provider IDs, amount, currency, and provider metadata. Webhooks remain the final authority and stay entirely on the platform.
Call giving.dispose() when the SDK is no longer needed. The application owns
the auth instance and should dispose it separately.
Run the example #
cd example
flutter run \
--dart-define=THEFAITHAPP_API_KEY=your-client-key \
--dart-define=THEFAITHAPP_CAMPAIGN_ID=42
Omit THEFAITHAPP_CAMPAIGN_ID to show only general giving. The example never
contains an API key, member identity, provider secret, or webhook secret in
source control.
License #
TheFaithApp Giving is available under the MIT License.