Migrating from Square
This guide is for teams moving an existing Square integration to Flint without rebuilding every payment flow at once.
The main shift is structural:
- Square integrations often start from
CreatePayment,CreatePaymentLink,CreateInvoice,CreateSubscription, orCreateCard. - Flint starts from the business object that should stay authoritative:
order,invoice,payment_link, orsubscription_plan.
Square embedded flows use the Web Payments SDK to generate payment tokens for CreatePayment or CreateCard. Flint embedded and saved-card flows use Stripe.js and Stripe Elements instead, so your frontend tokenization code is not reusable as-is.
Square to Flint Object Map#
| Square | Flint |
|---|---|
| Customer | Customer |
| Order | Order |
| Card | Payment Method |
| Payment | Payment Intent |
Checkout API CreatePaymentLink | POST /v1/payment-links or POST /v1/checkout-sessions |
| Subscription plan variation | Subscription Plan |
| Subscription | Subscription |
| Invoice | Invoice |
| Payment refund | Refund |
| Webhook subscription | Webhook endpoint |
| Catalog product | Product |
Pick the Right Flint Primitive#
Use:
payment-linkswhen you want one reusable public URL for many buyerscheckout-sessionswhen your app creates one hosted checkout flow for one buyer, one order, or one subscription signuppayment-intentswhen you keep checkout on your own sitepayment-methodswhen you need a saved card for repeat charges or subscriptionssubscription-plansplussubscriptionswhen your app owns recurring billinginvoiceswhen the problem is receivables, due dates, reminders, hosted invoice payment, PDFs, or manual payment recording
1. Migrate Square Payment Links and Hosted Checkout#
Common Square shape:
- call Checkout API
CreatePaymentLink - send the hosted URL to buyers
- optionally sell a one-time amount, an order, or a subscription plan variation
Flint equivalent:
POST /v1/payment-linksfor one reusable public URLPOST /v1/checkout-sessionsif your app is creating a one-off hosted checkout for one buyer or one known order
Use a Flint payment link when the Square link is a reusable public sales page:
curl -X POST https://api.withflintpay.com/v1/payment-links \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: payment-link-consulting-001" \
-d '{
"name": "Consulting Session",
"line_items": [
{
"key": "consulting",
"name": "One-hour consulting session",
"quantity": 1,
"amount_money": { "amount": 15000, "currency": "USD" }
}
],
"customer": {
"require_email": true
},
"redirects": {
"success_redirect_url": "https://example.com/thanks"
}
}'
Use a Flint checkout session when your application starts the payment flow for one known order:
curl -X POST https://api.withflintpay.com/v1/checkout-sessions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: checkout-session-order-001" \
-d '{
"order_id": "ord_xxx",
"customer": {
"customer_id": "cus_xxx",
"require_email": true
},
"redirects": {
"success_redirect_url": "https://example.com/orders/success"
}
}'
If your Square integration calls CreatePaymentLink for each app-initiated checkout attempt, that is usually a Flint checkout-session migration, not a Flint payment-link migration.
2. Migrate Square Web Payments SDK plus CreatePayment#
Common Square shape:
- optionally create an order
- collect a payment token with the Web Payments SDK
- call
CreatePayment
Flint equivalent:
- Create an order.
- Create a payment intent.
- Mount Stripe Elements with the returned
client_secret. - Confirm payment with Stripe.js on the frontend.
- Verify the final order state from your backend.
Create the Order#
curl -X POST https://api.withflintpay.com/v1/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: order-square-migration-001" \
-d '{
"line_items": [
{
"name": "Premium Widget",
"quantity": 1,
"unit_price_money": { "amount": 2500, "currency": "USD" }
}
]
}'
Create the Payment Intent#
curl -X POST https://api.withflintpay.com/v1/payment-intents \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: pi-square-migration-001" \
-d '{
"order_id": "ord_xxx"
}'
Send these response fields to your frontend:
data.payment_intent.payment_intent_iddata.client_confirmation.stripe.client_secretdata.client_confirmation.stripe.account_id
Mount Stripe Elements#
const stripe = Stripe("pk_test_xxx", {
stripeAccount: accountIdFromBackend,
});
const elements = stripe.elements({
clientSecret: clientSecretFromBackend,
});
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
Confirm Payment with Stripe.js#
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: "https://example.com/orders/success",
},
});
stripe.confirmPayment(...) handles the Stripe-side confirmation for the order-linked payment intent returned by Flint.
Verify the Final State#
curl -X GET https://api.withflintpay.com/v1/orders/ord_xxx \
-H "Authorization: Bearer YOUR_API_KEY"
3. Migrate Square Cards API and Card-On-File Charges#
Common Square shape:
- create or search for a customer
- collect card details with the Web Payments SDK
- store the card with
CreateCard - charge later using
card_id
Flint equivalent:
- create or map the Flint customer
- create a Flint payment method for that customer
- confirm card setup with Stripe.js
- charge later using
payment_method_idor reuse it for subscriptions
Create the Customer#
curl -X POST https://api.withflintpay.com/v1/customers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: customer-square-migration-001" \
-d '{
"name": "Jane Doe",
"email": "jane@example.com",
"merchant_customer_id": "square_customer_123"
}'
Create the Payment Method Setup Intent#
curl -X POST https://api.withflintpay.com/v1/payment-methods \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: payment-method-square-migration-001" \
-d '{
"customer_id": "cus_xxx"
}'
The response includes:
data.client_setup.stripe.client_secretdata.client_setup.stripe.account_id
Initialize Stripe.js with the returned connected account, then confirm setup on the frontend. If you are using a card element flow, confirm it like this:
const stripe = Stripe("pk_test_xxx", {
stripeAccount: accountIdFromBackend,
});
await stripe.confirmCardSetup(clientSecretFromBackend, {
payment_method: {
card: cardElementFromYourUI,
},
});
If you are using a newer setup flow built around an elements instance, use stripe.confirmSetup(...) instead.
After setup completes and the payment method is available, reuse the returned Flint payment_method_id in:
POST /v1/subscriptionsPOST /v1/payment-intentsPOST /v1/payment-methods/{payment_method_id}/set-default
Example order-backed one-time charge with a saved payment method:
curl -X POST https://api.withflintpay.com/v1/payment-intents \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: payment-intent-card-on-file-001" \
-d '{
"order_id": "ord_xxx"
}'
Then pay the order using the saved Flint payment method:
curl -X POST https://api.withflintpay.com/v1/orders/ord_xxx/pay \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: pay-order-card-on-file-001" \
-d '{
"payment_intent_ids": ["pi_xxx"],
"payment_method_ids": {
"pi_xxx": "pm_xxx"
}
}'
4. Migrate Square Subscriptions#
Common Square shape:
- create a subscription plan and variation
- create or map a customer
- optionally store a card on file
- create a subscription or a hosted subscription checkout link
Flint equivalent:
- create one Flint subscription plan
- create or map the customer
- save a payment method
- create the subscription directly, or sell the plan through
checkout-sessionsorpayment-links
If you set the finished payment method as the customer's default after setup completes, later POST /v1/subscriptions calls can omit payment_method_id and Flint will use that default payment method instead.
Create the Plan#
curl -X POST https://api.withflintpay.com/v1/subscription-plans \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: create-plan-monthly-001" \
-d '{
"name": "Pro Monthly",
"billing_interval": "monthly",
"billing_interval_count": 1,
"currency": "USD",
"line_items": [
{
"name": "Pro Plan",
"unit_price_money": { "amount": 2999, "currency": "USD" },
"quantity": 1
}
]
}'
Create the Subscription#
curl -X POST https://api.withflintpay.com/v1/subscriptions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: subscription-square-migration-001" \
-d '{
"plan_id": "plan_xxx",
"customer_id": "cus_xxx",
"payment_method_id": "pm_xxx"
}'
If your Square flow used a hosted subscription checkout page, use one of these Flint hosted entry points instead:
POST /v1/checkout-sessionswithplan_idPOST /v1/payment-linkswithplan_id
5. Migrate Square Invoices#
Common Square shape:
- create an order
- create an invoice draft
- publish the invoice
- let Square host the payment page and manage the payment flow
Flint equivalent:
- create an invoice from
order_idorquick_pay - send it with
POST /v1/invoices/{invoice_id}/send - use
POST /v1/invoices/{invoice_id}/checkout-sessionwhen you need the Flint-hosted card collection flow for the current invoice balance
Create the Invoice Draft#
curl -X POST https://api.withflintpay.com/v1/invoices \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: invoice-square-migration-001" \
-d '{
"order_id": "ord_xxx",
"recipient_email": "billing@example.com",
"due_at": "2026-04-15T00:00:00Z",
"reference": "PO-1048"
}'
Send the Invoice#
curl -X POST https://api.withflintpay.com/v1/invoices/inv_xxx/send \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: invoice-send-square-migration-001" \
-d '{}'
Unlike Square invoice APIs, Flint also exposes an explicit invoice-owned checkout-session API if your app needs to bootstrap or reuse the hosted card collection flow for an already-issued invoice.
6. Migrate Square Refunds#
Common Square shape:
- refund by
payment_id - send a full or partial amount
Flint equivalent:
- refund by
payment_intent_idororder_id - omit
amount_moneyfor a full refund of the remaining refundable amount
curl -X POST https://api.withflintpay.com/v1/refunds \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: refund-square-migration-001" \
-d '{
"order_id": "ord_xxx",
"reason": "requested_by_customer",
"reason_message": "Customer canceled before fulfillment."
}'
Use payment_intent_id when your current Square code is organized around payment objects. Use order_id when the order remains your main refund and reconciliation unit.
7. Migrate Square Webhooks#
Map Square webhook handling to the Flint resource that now owns the workflow.
Common Flint events for migrated Square flows:
- payment success:
order.payment_succeededorpayment_intent.succeeded - checkout completion:
checkout_session.completed - refunds:
refund.created,refund.failed,refund.updated - subscriptions:
subscription.created,subscription.activated,subscription.payment_succeeded,subscription.payment_failed,subscription.canceled - invoices:
invoice.sent,invoice.paid,invoice.partially_paid,invoice.refunded,invoice.voided - saved cards:
payment_method.saved,payment_method.removed
Create the webhook endpoint:
curl -X POST https://api.withflintpay.com/v1/webhook-endpoints \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: webhook-square-migration-001" \
-d '{
"url": "https://example.com/flint/webhooks",
"enabled_events": [
"order.payment_succeeded",
"refund.created",
"subscription.payment_failed",
"invoice.paid"
],
"description": "Primary Flint webhook endpoint",
"enabled": true
}'
Do not assume Square-specific payment methods or SDK flows port 1:1. If your current integration depends on Cash App Pay, Square gift cards, or Terminal-specific flows, confirm the Flint payment method and device surface you want before you migrate that part.
Migration Checklist#
- Keep Square customer IDs and order IDs in Flint metadata or
merchant_customer_id. - Decide which flows should become
payment-links,checkout-sessions,payment-intents,invoices, or directsubscriptions. - Replace Web Payments SDK card tokenization with Stripe.js only for the embedded and saved-card flows that need it.
- Move webhook consumers to Flint event names before switching live traffic.
- Add
Idempotency-Keyto the Flint write paths that support it, especially create and retry-sensitive operations. Use the Idempotency guide as the source of truth for the current route list.
