REST endpoints for tap to pay in ServFlo: 8 operations with parameters, request and response fields, permissions and curl examples.
Base URL: https://app.servflo.ai/api. Every call needs Authorization: Bearer sfk_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.
Whether cards can be taken in person on a phone (Tap to Pay on iPhone and Android, through Stripe Terminal) and whether this caller may charge a customer's saved card. Read-only; makes nothing at Stripe. The technician app shows its Tap to Pay button only when available is true (and the phone supports it).
The business can take cards in person: Stripe connected, charges enabled, card payments active and a business address for the Terminal location.
reason
enum or null
Why not: no Stripe key on the server, no account, charges not enabled yet, card payments paused, or no business address. One of NOT_CONFIGURED, NOT_CONNECTED, NOT_ENABLED, CARD_PAYMENTS_INACTIVE, NO_ADDRESS.
problem
string or null
What to fix, in words, when reason is NO_ADDRESS.
mode
enum or null
test: use Stripe's simulated reader and test cards. One of test, live.
merchantDisplayName
string
The business name shown on the tap sheet.
locationReady
boolean
The Stripe Terminal location exists (made on first use).
tipsEnabled
boolean
techChargeSavedCards
boolean
The owner's switch "Let technicians charge saved cards" (default off).
canChargeSavedCards
boolean
This caller may charge a customer's saved card (always for the office).
POST /organizations/{organizationId}/invoices/{invoiceId}/tap-to-pay
Money: starts a card payment the customer taps on the technician's phone. Writes a PENDING payment (processor STRIPE, channel TAP_TO_PAY, payment.started) and a card_present PaymentIntent on the business's Stripe account for amountCents (default the balance due; less is allowed, at least 100) plus tipCents when the business takes tips. The phone collects the card with the Stripe Terminal SDK; Stripe's webhook settles the payment and the invoice (payment.recorded). An earlier unfinished Tap to Pay on this invoice is cancelled. 409 when the business can't take cards, 400 when nothing is due. Technicians: their own jobs' invoices.
POST /organizations/{organizationId}/quotes/{quoteId}/tap-to-pay
Money: starts a card deposit the customer taps on the phone, on an APPROVED (or CONVERTED, not yet invoiced) quote. Writes a PENDING deposit payment (channel TAP_TO_PAY) and a card_present PaymentIntent on the business's Stripe account for amountCents (default the deposit the approval asked for; deposits may add up to the approved total). Stripe's webhook settles it; the deposit moves onto the invoice when the quote is invoiced. Technicians: the quotes they sold.
POST /organizations/{organizationId}/payments/{paymentId}/tap-to-pay/cancel
The customer didn't tap, or the person stopped: cancels the PaymentIntent at Stripe and marks the PENDING Tap to Pay payment FAILED (payment.failed, reason tap_cancelled). Takes no money and refunds nothing; a payment Stripe already took is left for its webhook to settle. Technicians: payments they started.
GET /organizations/{organizationId}/payments/{paymentId}/in-person
The status of a Tap to Pay or saved-card payment (PENDING until Stripe settles it, SUCCEEDED, FAILED with a reason in words), its amount and the card (Visa •••• 4242). The app polls this after a tap. Read-only. Technicians: payments they took.
GET /organizations/{organizationId}/invoices/{invoiceId}/saved-card
The card the invoice's customer saved on the business's Stripe account (for memberships, from their portal), as brand, last four and expiry, and whether this caller may charge it now (allowed, else refusal in words: technicians need the owner's "Let technicians charge saved cards" switch; expired cards and bank accounts can't). Read-only. Technicians: their own jobs' invoices.
POST /organizations/{organizationId}/invoices/{invoiceId}/charge-saved-card
Money: charges the card the invoice's customer saved (GET /invoices/{invoiceId}/saved-card first) off-session on the business's Stripe account, for amountCents (default the balance due). Only after the person confirmed the amount with the customer. attemptKey is made once per confirmation: a retry with the same key charges once and returns the same payment. Writes a payment (channel SAVED_CARD, payment.started), settled from Stripe's answer: SUCCEEDED (payment.recorded) or FAILED with the reason (declined, expired, the bank asked the customer to confirm). Technicians only when the owner turned on "Let technicians charge saved cards" (409 otherwise). An AI caller always needs the person's approval in ServFlo.
POST /organizations/{organizationId}/payments/{paymentId}/receipt
Sends to the customer: a receipt for a Tap to Pay or saved-card payment that went through (amount, card, invoice or quote, PAY-n), by text (SMS) or EMAIL, through the engagement engine and its consent rules. Sent once per payment and channel (a repeat returns the first). 409 while the payment is still PENDING. In-person card payments don't trigger the automatic receipt; this is how the customer gets one. Technicians: payments they took.