Skip to main content
Business & GrowthPayment Services219 lines

Square

Accept payments with Square. Use this skill when the project needs to integrate

Quick Summary25 lines
You are a payments specialist who integrates Square into projects. Square offers a
unified platform for online payments, in-person POS, invoicing, and subscription
billing — making it ideal for businesses that sell both online and offline.

## Key Points

- Use idempotency keys on all mutating API calls — Square requires them
- Use the Web Payments SDK for PCI-compliant card tokenization
- Store Square customer IDs alongside your user records
- Use the Catalog API for product management — syncs across channels
- Test in sandbox with Square's test credentials
- Use reference_id on payments to link to your users
- Processing payments without idempotency keys — causes duplicates
- Building custom card forms instead of using Web Payments SDK
- Not verifying webhook signatures
- Hardcoding amounts instead of referencing catalog items
- Not handling refund webhooks

## Quick Example

```bash
npm install square
```
skilldb get payment-services-skills/SquareFull skill: 219 lines
Paste into your CLAUDE.md or agent config

Square Payment Integration

You are a payments specialist who integrates Square into projects. Square offers a unified platform for online payments, in-person POS, invoicing, and subscription billing — making it ideal for businesses that sell both online and offline.

Core Philosophy

Omnichannel by default

Square's strength is unifying online and in-person payments. Inventory, orders, customers, and catalog sync across channels. If your business has both a website and a physical presence, Square eliminates the integration gap.

Catalog-driven commerce

Square's Catalog API manages products, variations, pricing, and inventory. Orders reference catalog items, creating a consistent product model across online checkout, POS terminals, and invoices.

Web Payments SDK for custom checkout

Square's Web Payments SDK provides embeddable payment form components (card, Apple Pay, Google Pay, ACH) with full PCI compliance handled by Square's tokenization.

Setup

Install

npm install square

Initialize

import { Client, Environment } from 'square';

const client = new Client({
  accessToken: process.env.SQUARE_ACCESS_TOKEN,
  environment: process.env.NODE_ENV === 'production'
    ? Environment.Production
    : Environment.Sandbox,
});

Key Techniques

Web Payments SDK (card form)

<script src="https://sandbox.web.squarecdn.com/v1/square.js"></script>
<div id="card-container"></div>
<button id="pay-button">Pay $29.00</button>

<script>
const payments = Square.payments('sandbox-sq0idb-xxx', 'location-id');
const card = await payments.card();
await card.attach('#card-container');

document.getElementById('pay-button').onclick = async () => {
  const result = await card.tokenize();
  if (result.status === 'OK') {
    const res = await fetch('/api/square/create-payment', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ sourceId: result.token, amount: 2900 }),
    });
  }
};
</script>

Create payment (server-side)

const { result } = await client.paymentsApi.createPayment({
  sourceId: tokenFromClient,
  idempotencyKey: crypto.randomUUID(),
  amountMoney: {
    amount: BigInt(2900), // $29.00 in cents
    currency: 'USD',
  },
  locationId: process.env.SQUARE_LOCATION_ID,
  referenceId: userId,
  note: 'Pro Plan - Monthly',
});

const paymentId = result.payment.id;

Subscriptions

// Create subscription plan (catalog)
const { result: plan } = await client.catalogApi.upsertCatalogObject({
  idempotencyKey: crypto.randomUUID(),
  object: {
    type: 'SUBSCRIPTION_PLAN',
    id: '#pro-monthly',
    subscriptionPlanData: {
      name: 'Pro Monthly',
      phases: [{
        cadence: 'MONTHLY',
        recurringPriceMoney: { amount: BigInt(2900), currency: 'USD' },
      }],
    },
  },
});

// Create subscription
const { result: sub } = await client.subscriptionsApi.createSubscription({
  idempotencyKey: crypto.randomUUID(),
  locationId: process.env.SQUARE_LOCATION_ID,
  planVariationId: planVariationId,
  customerId: squareCustomerId,
  cardId: cardId,
});

// Cancel subscription
await client.subscriptionsApi.cancelSubscription(subscriptionId);

Customer management

// Create customer
const { result } = await client.customersApi.createCustomer({
  emailAddress: 'user@example.com',
  givenName: 'Alice',
  referenceId: userId,
});

// Store card on file
const { result: card } = await client.cardsApi.createCard({
  idempotencyKey: crypto.randomUUID(),
  sourceId: tokenFromClient,
  card: { customerId: result.customer.id },
});

Invoices

const { result: invoice } = await client.invoicesApi.createInvoice({
  invoice: {
    locationId: process.env.SQUARE_LOCATION_ID,
    orderId: orderId,
    primaryRecipient: { customerId: squareCustomerId },
    paymentRequests: [{
      requestType: 'BALANCE',
      dueDate: '2025-04-01',
      automaticPaymentSource: 'CARD_ON_FILE',
    }],
    deliveryMethod: 'EMAIL',
  },
  idempotencyKey: crypto.randomUUID(),
});

await client.invoicesApi.publishInvoice(invoice.invoice.id, {
  version: invoice.invoice.version,
});

Webhook Processing

EventAction
payment.completedGrant access
payment.failedNotify user
subscription.createdSet up subscription
subscription.updatedUpdate status
invoice.payment_madeMark invoice paid
refund.createdAdjust access
import crypto from 'crypto';

export async function POST(req: Request) {
  const body = await req.text();
  const signature = req.headers.get('x-square-hmacsha256-signature');
  const url = 'https://yourdomain.com/api/webhooks/square';

  const hmac = crypto.createHmac('sha256', process.env.SQUARE_WEBHOOK_SIGNATURE_KEY)
    .update(url + body)
    .digest('base64');

  if (hmac !== signature) {
    return new Response('Invalid signature', { status: 401 });
  }

  const event = JSON.parse(body);

  switch (event.type) {
    case 'payment.completed':
      await grantAccess(event.data.object.payment.reference_id);
      break;
  }

  return new Response('OK');
}

Best Practices

  • Use idempotency keys on all mutating API calls — Square requires them
  • Use the Web Payments SDK for PCI-compliant card tokenization
  • Store Square customer IDs alongside your user records
  • Use the Catalog API for product management — syncs across channels
  • Test in sandbox with Square's test credentials
  • Use reference_id on payments to link to your users

Anti-Patterns

  • Processing payments without idempotency keys — causes duplicates
  • Building custom card forms instead of using Web Payments SDK
  • Not verifying webhook signatures
  • Hardcoding amounts instead of referencing catalog items
  • Not handling refund webhooks

Install this skill directly: skilldb add payment-services-skills

Get CLI access →