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, or CreateCard.
  • Flint starts from the business object that should stay authoritative: order, invoice, payment_link, or subscription_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#

SquareFlint
CustomerCustomer
OrderOrder
CardPayment Method
PaymentPayment Intent
Checkout API CreatePaymentLinkPOST /v1/payment-links or POST /v1/checkout-sessions
Subscription plan variationSubscription Plan
SubscriptionSubscription
InvoiceInvoice
Payment refundRefund
Webhook subscriptionWebhook endpoint
Catalog productProduct

Pick the Right Flint Primitive#

Use:

  • payment-links when you want one reusable public URL for many buyers
  • checkout-sessions when your app creates one hosted checkout flow for one buyer, one order, or one subscription signup
  • payment-intents when you keep checkout on your own site
  • payment-methods when you need a saved card for repeat charges or subscriptions
  • subscription-plans plus subscriptions when your app owns recurring billing
  • invoices when the problem is receivables, due dates, reminders, hosted invoice payment, PDFs, or manual payment recording

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-links for one reusable public URL
  • POST /v1/checkout-sessions if 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:

Bash
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:

Bash
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:

  1. Create an order.
  2. Create a payment intent.
  3. Mount Stripe Elements with the returned client_secret.
  4. Confirm payment with Stripe.js on the frontend.
  5. Verify the final order state from your backend.

Create the Order#

Bash
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#

Bash
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_id
  • data.client_confirmation.stripe.client_secret
  • data.client_confirmation.stripe.account_id

Mount Stripe Elements#

JavaScript
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#

JavaScript
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#

Bash
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_id or reuse it for subscriptions

Create the Customer#

Bash
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#

Bash
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_secret
  • data.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:

JavaScript
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/subscriptions
  • POST /v1/payment-intents
  • POST /v1/payment-methods/{payment_method_id}/set-default

Example order-backed one-time charge with a saved payment method:

Bash
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:

Bash
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-sessions or payment-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#

Bash
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#

Bash
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-sessions with plan_id
  • POST /v1/payment-links with plan_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_id or quick_pay
  • send it with POST /v1/invoices/{invoice_id}/send
  • use POST /v1/invoices/{invoice_id}/checkout-session when you need the Flint-hosted card collection flow for the current invoice balance

Create the Invoice Draft#

Bash
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#

Bash
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_id or order_id
  • omit amount_money for a full refund of the remaining refundable amount
Bash
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_succeeded or payment_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:

Bash
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#

  1. Keep Square customer IDs and order IDs in Flint metadata or merchant_customer_id.
  2. Decide which flows should become payment-links, checkout-sessions, payment-intents, invoices, or direct subscriptions.
  3. Replace Web Payments SDK card tokenization with Stripe.js only for the embedded and saved-card flows that need it.
  4. Move webhook consumers to Flint event names before switching live traffic.
  5. Add Idempotency-Key to 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.

Next Guides#

Rate this doc