Pay In Payment Flow
Pay In Payment Flow is Payabli’s native mobile UI for card and ACH payments in your app. It owns sensitive field state and renders a hosted form, so your app never touches raw card or bank data. See Tap to Pay if you’re looking for Payabli’s contactless payment component instead.
Right now, only iOS is supported.
Prerequisites
Before you start, confirm you have:
- Xcode 15 or later and Swift 5.9 or later
- iOS 16.7 or later as your deployment target
- A Payabli sandbox
entryPointwith card and ACH enabled - A Payabli
clientIdandclientSecret. See OAuth authentication to provision them.
Installation
Install PayabliSDKPayInPaymentFlow from the sdk-ios Swift package:
Backend token endpoint
The Pay In Payment Flow component authenticates every request with a short-lived Payabli access token, obtained through an accessTokenProvider closure you implement.
Your backend holds the Payabli clientId and clientSecret, exchanges them for the access token, and never exposes them to your mobile app.
Create the project
This example server uses JavaScript with Node.js and Express.
Create a new Node.js project and enable ES modules:
Write the token endpoint
Create server.js with the following:
Store clientId and clientSecret in environment variables on your server. Never commit them to source control.
Call it from your app
The accessTokenProvider closure calls this endpoint and returns the token:
The component calls this closure fresh before every request, so it never sends a stale token. You don’t need to cache the token yourself. If a request still fails with a 401 Unauthorized response, the error surfaces through onError — resubmitting calls the closure again for a new token.
Operations
PayabliPayInPaymentFlow’s operation parameter selects the hosted form’s behavior:
.storePaymentMethod— Tokenizes a card or ACH account for later use, without charging it..capture— Authorizes and captures a card or ACH payment in one step..authorize— Authorizes a card payment without capturing it. Card only. ACH and stored payment methods are rejected before the request is sent.
Implementation walkthrough
This walkthrough builds a minimal card or ACH capture, from constructing PayabliPayInPaymentFlow through rendering the hosted form:
/// Add the import
Import PayabliSDKPayInPaymentFlow and create a view model that holds the component. You can design your own API client and view model conventions. This walkthrough uses a minimal ObservableObject.
/// Implement the backend token provider
Add a function that calls your backend’s token endpoint and returns a Payabli mobile access token. Your backend holds the Payabli clientSecret, not the app.
/// Create the Pay In Payment Flow component
Construct PayabliPayInPaymentFlow in .capture mode. Pass your accessTokenProvider closure and a requestConfiguration describing the amount to charge.
/// Render the hosted form and handle the result
Add a view that renders PayabliPayInPaymentFlowView and logs the result. The hosted form collects card or ACH details itself. Your view never sees raw card data.
Implementation reference
PayabliPayInPaymentFlowFormConfiguration and PayabliPayInPaymentFlowRequestConfiguration control field layout, labels, and request data for every operation. PayabliPayInPaymentFlowSheetConfiguration controls the sheet presentation.
PayabliPayInPaymentFlowFormConfiguration fields
This hosted form is shared by all three operations. See Operations for what each one does.
Hosted methods the payor can select. For .authorize, this is normalized to card only.
Initial selected method. Falls back to the first allowed method if .card isn’t allowed.
Custom section grouping for card fields. Required and payment-summary fields are appended automatically if missing.
properties
Optional stable identifier. Defaults to the section title or its joined field names.
Section title, for example Card Information.
Per-section text style override.
Ordered PayabliPayInPaymentFlowField values in this section.
Vertical spacing between inputs in this section.
Horizontal spacing for paired inputs in this section.
Per-field vertical spacing overrides, keyed by field.
Custom section grouping for ACH fields. achSecCode is never rendered, even if listed.
properties
Optional stable identifier. Defaults to the section title or its joined field names.
Section title, for example Card Information.
Per-section text style override.
Ordered PayabliPayInPaymentFlowField values in this section.
Vertical spacing between inputs in this section.
Horizontal spacing for paired inputs in this section.
Per-field vertical spacing overrides, keyed by field.
Flat card field order, used only when cardSections is nil.
Flat ACH field order, used only when achSections is nil.
Values submitted with the form without rendering an editable field.
properties
.personal or .business.
.ppd, .web, .tel, .ccd, or .boc.
Default or hidden customer data, merged with any visible customer fields.
properties
Custom identifier fields, when the paypoint uses custom identifiers instead of name/email/customer ID.
Title, subtitle, submit button text, field labels, and placeholders.
properties
Visible and accessibility label text, keyed by PayabliPayInPaymentFlowField.
Placeholder text, keyed by PayabliPayInPaymentFlowField.
.external shows visible labels. .placeholder uses placeholder-first inputs.
Global visible-label override. Leave unset to follow labelLayout.
Fields to hide the visible label for. Accessibility labels are unaffected.
Card number spacing, expiration separator, and ACH account masking.
properties
Adds visual card number grouping.
Separator used in expiration entry. An empty string resolves to /.
Masks ACH account entry in the hosted field.
Default and per-field input sizes. Height is clamped to the accessibility minimum touch target.
properties
Default PayabliPayInPaymentFlowInputSize: optional width, height (default 52), and horizontalPadding (default 14).
Per-field PayabliPayInPaymentFlowInputSize overrides, keyed by PayabliPayInPaymentFlowField.
.leading, .trailing, or .hidden.
.top or .aboveSubmitButton.
Optional visible fields to require. .amount is always required.
Read-only amount and fee display for capture and authorize forms.
properties
Font and color for the label text.
Font and color for the value text.
Card, ACH, customer, and payment-summary fields available for fields, cardFieldOrder, achFieldOrder, requiredFields, and hiddenFieldLabels.
cases
achSections.PayabliPayInPaymentFlowRequestConfiguration fields
Used by hosted capture and authorize forms, and by the direct capture/authorize/authorized-capture APIs. Not used for .storePaymentMethod.
properties
Must be greater than 0.
Must not be negative.
For example, USD.
Defaults merged with form-entered customer data.
properties
Custom identifier fields, when the paypoint uses custom identifiers instead of name/email/customer ID.
Client-side validation, run before a request is sent.
properties
Runs a Luhn check on card numbers.
Runs an ABA checksum on ACH routing numbers.
PayabliPayInPaymentFlowSheetConfiguration fields
Controls the sheet presentation for .payabliPayInPaymentFlowSheet(...). The sheet wraps the same hosted form as PayabliPayInPaymentFlowView, so configuration, requestConfiguration, and style still apply:
Sheet title. Falls back to the form’s labels.title when movesFormHeaderToSheetHeader is true.
Sheet subtitle. Falls back to the form’s labels.subtitle when movesFormHeaderToSheetHeader is true.
.close, .back, or .hidden.
Dismisses the sheet automatically after onCompleted fires.
SwiftUI presentation detents. An empty set resolves to .large.
SwiftUI drag indicator visibility.
Padding around the sheet’s content.
Moves the form’s title and subtitle into the sheet header instead of rendering them inline.
Adds a detent sized to the form’s measured content height, when it fits.
Expands to .large if the form’s content doesn’t fit the selected detent.
Response reference
PayabliPayInPaymentFlowResult is a unified wrapper for both token-storage and transaction operations.
.storedPaymentMethod or .transaction.
Stored-method result code, or MoneyIn response code.
Human-readable result or failure reason, when the backend returns one.
Present for .transaction results. Additional detail beyond reason.
Present for .transaction results. Suggested next step, when the backend returns one.
Present when kind is .storedPaymentMethod.
properties
Present when kind is .transaction. Covers capture, authorize, and capture-authorized results.
properties
Processor-level response detail. See Make a transaction (v2) for the underlying field semantics.
properties
Present for .transaction results. The raw response the transaction fields above were parsed from.
properties
Same shape as transaction above.
Theming & diagnostics
Style the hosted form to match your app and inspect network activity for debugging:
Style
Use PayabliPayInPaymentFlowStyle to style the hosted form. Pass it directly to PayabliPayInPaymentFlowView or .payabliPayInPaymentFlowSheet(...), or inject it with .payabliPayInPaymentFlowStyle(_:).
To use a custom font:
Diagnostics
Diagnostics are disabled by default. Enable them for local debugging or QA. Don’t enable them in production builds shipped to end users.
Each PayabliPayInPaymentFlowDiagnosticEntry includes phase (.request, .response, .failure), timestamp, method, url, statusCode, headers, body, durationMilliseconds, and errorDescription.
Diagnostics redact authorization headers, access and request tokens, card number, CVV, ACH account and routing numbers, stored method IDs, customer identifiers, names, emails, phones, and addresses before they reach your handler. You don’t need to add more redaction yourself, but don’t log the redacted output somewhere less secure than the app itself.
Example app
The sdk-ios repository includes PayabliDemo, a SwiftUI example app that exercises PayabliPayInPaymentFlow and PayabliTTP (card/ACH capture and Tap to Pay), alongside a bundled local Node.js token server for testing.
Configure your secrets
Copy the secrets template, then fill in your sandbox identifiers and configure Pay In Payment Flow to use the bundled local token server:
/// Set your sandbox identifiers
Copy Secrets.swift.sample to Secrets.swift, then set your sandbox entryPoint and appId (<TEAM_ID>.<BUNDLE_ID>):
/// Configure Pay In Payment Flow to use the local token server
fetchPaymentMethodAccessToken() calls partnerPaymentMethodAccessTokenEndpoint. Set it to the bundled LocalTokenServer so the Pay In Payment Flow tabs work without a real backend:
Start the local token server
In a separate terminal, start the bundled LocalTokenServer:
Edit .env and set PAYABLI_ACCESS_TOKEN to a short-lived sandbox access token, then start the server:
See the LocalTokenServer README for the credential-exchange mode and physical-device networking notes.
Run the app
Open PayabliDemo.xcodeproj in Xcode, select the PayabliDemo scheme, and run it. The Pay In Payment Flow tabs work in the Simulator. Tap to Pay requires a physical device. See Requirements.
The example app assumes a sandbox entryPoint with card, ACH, and Tap to Pay enabled. Contact your Payabli representative if your sandbox paypoint doesn’t have these enabled yet.
Related resources
See these related resources to help you get the most out of Payabli.
Prerequisites
- Mobile components overview - Learn how Payabli’s native mobile SDK components let you accept payments in your iOS app