From 339ec6e266e61911d7187a2f3ce1729a903bcb1e Mon Sep 17 00:00:00 2001 From: waleed Date: Sun, 14 Jun 2026 23:16:56 -0700 Subject: [PATCH 1/7] feat(square): add Square integration with 34 commerce operations Add a Square integration (API-key auth via personal access token) covering payments, refunds, customers, locations, orders, invoices, catalog, and inventory. Catalog image upload routes through an internal API endpoint using the shared UserFile handling pattern. Adds a dedicated square-errors extractor. --- apps/docs/components/icons.tsx | 11 + apps/docs/components/ui/icon-mapping.ts | 2 + .../content/docs/en/integrations/meta.json | 1 + .../content/docs/en/integrations/square.mdx | 1472 +++++++++++++++++ .../api/tools/square/catalog-image/route.ts | 121 ++ apps/sim/blocks/blocks/square.ts | 877 ++++++++++ apps/sim/blocks/registry.ts | 3 + apps/sim/components/icons.tsx | 11 + apps/sim/lib/api/contracts/tools/index.ts | 1 + apps/sim/lib/api/contracts/tools/square.ts | 45 + apps/sim/lib/integrations/icon-mapping.ts | 2 + apps/sim/lib/integrations/integrations.json | 155 ++ apps/sim/tools/error-extractors.ts | 12 + apps/sim/tools/registry.ts | 70 + .../square/batch_retrieve_inventory_counts.ts | 91 + apps/sim/tools/square/cancel_invoice.ts | 71 + apps/sim/tools/square/cancel_payment.ts | 65 + apps/sim/tools/square/complete_payment.ts | 65 + apps/sim/tools/square/create_catalog_image.ts | 98 ++ apps/sim/tools/square/create_customer.ts | 127 ++ apps/sim/tools/square/create_invoice.ts | 75 + apps/sim/tools/square/create_order.ts | 75 + apps/sim/tools/square/create_payment.ts | 132 ++ .../sim/tools/square/delete_catalog_object.ts | 62 + apps/sim/tools/square/delete_customer.ts | 49 + apps/sim/tools/square/delete_invoice.ts | 60 + apps/sim/tools/square/get_catalog_object.ts | 78 + apps/sim/tools/square/get_customer.ts | 64 + apps/sim/tools/square/get_invoice.ts | 63 + apps/sim/tools/square/get_location.ts | 60 + apps/sim/tools/square/get_order.ts | 63 + apps/sim/tools/square/get_payment.ts | 63 + apps/sim/tools/square/get_refund.ts | 63 + apps/sim/tools/square/index.ts | 34 + apps/sim/tools/square/list_catalog.ts | 78 + apps/sim/tools/square/list_customers.ts | 91 + apps/sim/tools/square/list_invoices.ts | 84 + apps/sim/tools/square/list_locations.ts | 56 + apps/sim/tools/square/list_payments.ts | 98 ++ apps/sim/tools/square/list_refunds.ts | 105 ++ apps/sim/tools/square/pay_order.ts | 90 + apps/sim/tools/square/publish_invoice.ts | 81 + apps/sim/tools/square/refund_payment.ts | 97 ++ .../tools/square/search_catalog_objects.ts | 96 ++ apps/sim/tools/square/search_customers.ts | 86 + apps/sim/tools/square/search_invoices.ts | 88 + apps/sim/tools/square/search_orders.ts | 94 ++ apps/sim/tools/square/types.ts | 1070 ++++++++++++ apps/sim/tools/square/update_customer.ts | 124 ++ .../sim/tools/square/upsert_catalog_object.ts | 78 + scripts/check-api-validation-contracts.ts | 4 +- 51 files changed, 6659 insertions(+), 2 deletions(-) create mode 100644 apps/docs/content/docs/en/integrations/square.mdx create mode 100644 apps/sim/app/api/tools/square/catalog-image/route.ts create mode 100644 apps/sim/blocks/blocks/square.ts create mode 100644 apps/sim/lib/api/contracts/tools/square.ts create mode 100644 apps/sim/tools/square/batch_retrieve_inventory_counts.ts create mode 100644 apps/sim/tools/square/cancel_invoice.ts create mode 100644 apps/sim/tools/square/cancel_payment.ts create mode 100644 apps/sim/tools/square/complete_payment.ts create mode 100644 apps/sim/tools/square/create_catalog_image.ts create mode 100644 apps/sim/tools/square/create_customer.ts create mode 100644 apps/sim/tools/square/create_invoice.ts create mode 100644 apps/sim/tools/square/create_order.ts create mode 100644 apps/sim/tools/square/create_payment.ts create mode 100644 apps/sim/tools/square/delete_catalog_object.ts create mode 100644 apps/sim/tools/square/delete_customer.ts create mode 100644 apps/sim/tools/square/delete_invoice.ts create mode 100644 apps/sim/tools/square/get_catalog_object.ts create mode 100644 apps/sim/tools/square/get_customer.ts create mode 100644 apps/sim/tools/square/get_invoice.ts create mode 100644 apps/sim/tools/square/get_location.ts create mode 100644 apps/sim/tools/square/get_order.ts create mode 100644 apps/sim/tools/square/get_payment.ts create mode 100644 apps/sim/tools/square/get_refund.ts create mode 100644 apps/sim/tools/square/index.ts create mode 100644 apps/sim/tools/square/list_catalog.ts create mode 100644 apps/sim/tools/square/list_customers.ts create mode 100644 apps/sim/tools/square/list_invoices.ts create mode 100644 apps/sim/tools/square/list_locations.ts create mode 100644 apps/sim/tools/square/list_payments.ts create mode 100644 apps/sim/tools/square/list_refunds.ts create mode 100644 apps/sim/tools/square/pay_order.ts create mode 100644 apps/sim/tools/square/publish_invoice.ts create mode 100644 apps/sim/tools/square/refund_payment.ts create mode 100644 apps/sim/tools/square/search_catalog_objects.ts create mode 100644 apps/sim/tools/square/search_customers.ts create mode 100644 apps/sim/tools/square/search_invoices.ts create mode 100644 apps/sim/tools/square/search_orders.ts create mode 100644 apps/sim/tools/square/types.ts create mode 100644 apps/sim/tools/square/update_customer.ts create mode 100644 apps/sim/tools/square/upsert_catalog_object.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index dc3c91c5bef..2d6b6eb2c03 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -1958,6 +1958,17 @@ export function WhatsAppIcon(props: SVGProps) { ) } +export function SquareIcon(props: SVGProps) { + return ( + + + + ) +} + export function StripeIcon(props: SVGProps) { return ( = { slack: SlackIcon, smtp: SmtpIcon, sqs: SQSIcon, + square: SquareIcon, ssh: SshIcon, stagehand: StagehandIcon, stripe: StripeIcon, diff --git a/apps/docs/content/docs/en/integrations/meta.json b/apps/docs/content/docs/en/integrations/meta.json index 0ee2e26089d..ab898490da8 100644 --- a/apps/docs/content/docs/en/integrations/meta.json +++ b/apps/docs/content/docs/en/integrations/meta.json @@ -192,6 +192,7 @@ "slack", "smtp", "sqs", + "square", "ssh", "stagehand", "stripe", diff --git a/apps/docs/content/docs/en/integrations/square.mdx b/apps/docs/content/docs/en/integrations/square.mdx new file mode 100644 index 00000000000..457f42e1843 --- /dev/null +++ b/apps/docs/content/docs/en/integrations/square.mdx @@ -0,0 +1,1472 @@ +--- +title: Square +description: Process payments and manage Square commerce data +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Usage Instructions + +Integrate Square into the workflow. Take and refund payments, manage customers, build catalog items and images, create and search orders, and issue invoices. Authenticate with a Square access token (personal access token). + + + +## Actions + +### `square_create_payment` + +Take a payment using a payment source such as a card nonce or a card on file + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `sourceId` | string | Yes | ID of the payment source \(card nonce, card-on-file ID, or wallet token\) | +| `amount` | number | Yes | Amount in the smallest currency denomination \(e.g. 1000 = $10.00\) | +| `currency` | string | Yes | Three-letter ISO 4217 currency code \(e.g. USD\) | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | +| `customerId` | string | No | ID of the customer associated with the payment | +| `locationId` | string | No | ID of the location where the payment is taken \(defaults to the main location\) | +| `orderId` | string | No | ID of the order associated with the payment | +| `referenceId` | string | No | Optional external reference for the payment | +| `note` | string | No | Optional note attached to the payment | +| `autocomplete` | boolean | No | Whether to immediately capture the payment \(defaults to true\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `payment` | object | The created payment object | +| ↳ `id` | string | Unique ID for the payment | +| ↳ `status` | string | Payment status \(APPROVED, PENDING, COMPLETED, CANCELED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `approved_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `app_fee_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `refunded_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `source_type` | string | Source of the payment \(CARD, BANK_ACCOUNT, WALLET, etc.\) | +| ↳ `card_details` | json | Details about a card payment | +| ↳ `location_id` | string | ID of the location where the payment was taken | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `reference_id` | string | Optional external reference for the payment | +| ↳ `receipt_number` | string | Receipt number for the payment | +| ↳ `receipt_url` | string | URL of the payment receipt | +| ↳ `note` | string | Optional note attached to the payment | +| ↳ `refund_ids` | array | IDs of refunds associated with the payment | +| ↳ `processing_fee` | array | Processing fees applied to the payment | +| ↳ `created_at` | string | Timestamp when the payment was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the payment was last updated \(RFC 3339\) | +| ↳ `version_token` | string | Optimistic concurrency token for the payment | +| `metadata` | json | Payment summary metadata | +| ↳ `id` | string | Square payment ID | +| ↳ `status` | string | Current payment status | +| ↳ `order_id` | string | Associated order ID | + +### `square_get_payment` + +Retrieve details for a single payment by its ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `paymentId` | string | Yes | ID of the payment to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `payment` | object | The retrieved payment object | +| ↳ `id` | string | Unique ID for the payment | +| ↳ `status` | string | Payment status \(APPROVED, PENDING, COMPLETED, CANCELED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `approved_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `app_fee_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `refunded_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `source_type` | string | Source of the payment \(CARD, BANK_ACCOUNT, WALLET, etc.\) | +| ↳ `card_details` | json | Details about a card payment | +| ↳ `location_id` | string | ID of the location where the payment was taken | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `reference_id` | string | Optional external reference for the payment | +| ↳ `receipt_number` | string | Receipt number for the payment | +| ↳ `receipt_url` | string | URL of the payment receipt | +| ↳ `note` | string | Optional note attached to the payment | +| ↳ `refund_ids` | array | IDs of refunds associated with the payment | +| ↳ `processing_fee` | array | Processing fees applied to the payment | +| ↳ `created_at` | string | Timestamp when the payment was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the payment was last updated \(RFC 3339\) | +| ↳ `version_token` | string | Optimistic concurrency token for the payment | +| `metadata` | json | Payment summary metadata | +| ↳ `id` | string | Square payment ID | +| ↳ `status` | string | Current payment status | +| ↳ `order_id` | string | Associated order ID | + +### `square_list_payments` + +List payments taken by the account, optionally filtered by location and time range + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `locationId` | string | No | Filter payments by location ID | +| `beginTime` | string | No | RFC 3339 timestamp for the beginning of the reporting period | +| `endTime` | string | No | RFC 3339 timestamp for the end of the reporting period | +| `limit` | number | No | Maximum number of results to return per page | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `payments` | array | Array of payment objects | +| ↳ `id` | string | Unique ID for the payment | +| ↳ `status` | string | Payment status \(APPROVED, PENDING, COMPLETED, CANCELED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `approved_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `app_fee_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `refunded_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `source_type` | string | Source of the payment \(CARD, BANK_ACCOUNT, WALLET, etc.\) | +| ↳ `card_details` | json | Details about a card payment | +| ↳ `location_id` | string | ID of the location where the payment was taken | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `reference_id` | string | Optional external reference for the payment | +| ↳ `receipt_number` | string | Receipt number for the payment | +| ↳ `receipt_url` | string | URL of the payment receipt | +| ↳ `note` | string | Optional note attached to the payment | +| ↳ `refund_ids` | array | IDs of refunds associated with the payment | +| ↳ `processing_fee` | array | Processing fees applied to the payment | +| ↳ `created_at` | string | Timestamp when the payment was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the payment was last updated \(RFC 3339\) | +| ↳ `version_token` | string | Optimistic concurrency token for the payment | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_cancel_payment` + +Cancel (void) an authorized payment that has not been captured + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `paymentId` | string | Yes | ID of the payment to cancel | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `payment` | object | The canceled payment object | +| ↳ `id` | string | Unique ID for the payment | +| ↳ `status` | string | Payment status \(APPROVED, PENDING, COMPLETED, CANCELED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `approved_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `app_fee_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `refunded_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `source_type` | string | Source of the payment \(CARD, BANK_ACCOUNT, WALLET, etc.\) | +| ↳ `card_details` | json | Details about a card payment | +| ↳ `location_id` | string | ID of the location where the payment was taken | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `reference_id` | string | Optional external reference for the payment | +| ↳ `receipt_number` | string | Receipt number for the payment | +| ↳ `receipt_url` | string | URL of the payment receipt | +| ↳ `note` | string | Optional note attached to the payment | +| ↳ `refund_ids` | array | IDs of refunds associated with the payment | +| ↳ `processing_fee` | array | Processing fees applied to the payment | +| ↳ `created_at` | string | Timestamp when the payment was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the payment was last updated \(RFC 3339\) | +| ↳ `version_token` | string | Optimistic concurrency token for the payment | +| `metadata` | json | Payment summary metadata | +| ↳ `id` | string | Square payment ID | +| ↳ `status` | string | Current payment status | +| ↳ `order_id` | string | Associated order ID | + +### `square_complete_payment` + +Capture (complete) a payment that was authorized with delayed capture + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `paymentId` | string | Yes | ID of the payment to complete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `payment` | object | The completed payment object | +| ↳ `id` | string | Unique ID for the payment | +| ↳ `status` | string | Payment status \(APPROVED, PENDING, COMPLETED, CANCELED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `approved_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `app_fee_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `refunded_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `source_type` | string | Source of the payment \(CARD, BANK_ACCOUNT, WALLET, etc.\) | +| ↳ `card_details` | json | Details about a card payment | +| ↳ `location_id` | string | ID of the location where the payment was taken | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `reference_id` | string | Optional external reference for the payment | +| ↳ `receipt_number` | string | Receipt number for the payment | +| ↳ `receipt_url` | string | URL of the payment receipt | +| ↳ `note` | string | Optional note attached to the payment | +| ↳ `refund_ids` | array | IDs of refunds associated with the payment | +| ↳ `processing_fee` | array | Processing fees applied to the payment | +| ↳ `created_at` | string | Timestamp when the payment was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the payment was last updated \(RFC 3339\) | +| ↳ `version_token` | string | Optimistic concurrency token for the payment | +| `metadata` | json | Payment summary metadata | +| ↳ `id` | string | Square payment ID | +| ↳ `status` | string | Current payment status | +| ↳ `order_id` | string | Associated order ID | + +### `square_refund_payment` + +Refund all or part of a completed payment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `paymentId` | string | Yes | ID of the payment to refund | +| `amount` | number | Yes | Amount to refund in the smallest currency denomination \(e.g. 100 = $1.00\) | +| `currency` | string | Yes | Three-letter ISO 4217 currency code \(e.g. USD\) | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | +| `reason` | string | No | Reason for the refund | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `refund` | object | The created refund object | +| ↳ `id` | string | Unique ID for the refund | +| ↳ `status` | string | Refund status \(PENDING, COMPLETED, REJECTED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `processing_fee` | array | Processing fees refunded | +| ↳ `payment_id` | string | ID of the payment being refunded | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `location_id` | string | ID of the associated location | +| ↳ `reason` | string | Reason for the refund | +| ↳ `created_at` | string | Timestamp when the refund was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the refund was last updated \(RFC 3339\) | +| `metadata` | json | Refund summary metadata | +| ↳ `id` | string | Square refund ID | +| ↳ `status` | string | Current refund status | +| ↳ `payment_id` | string | Refunded payment ID | + +### `square_get_refund` + +Retrieve a single payment refund by its ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `refundId` | string | Yes | ID of the refund to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `refund` | object | The retrieved refund object | +| ↳ `id` | string | Unique ID for the refund | +| ↳ `status` | string | Refund status \(PENDING, COMPLETED, REJECTED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `processing_fee` | array | Processing fees refunded | +| ↳ `payment_id` | string | ID of the payment being refunded | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `location_id` | string | ID of the associated location | +| ↳ `reason` | string | Reason for the refund | +| ↳ `created_at` | string | Timestamp when the refund was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the refund was last updated \(RFC 3339\) | +| `metadata` | json | Refund summary metadata | +| ↳ `id` | string | Square refund ID | +| ↳ `status` | string | Current refund status | +| ↳ `payment_id` | string | Refunded payment ID | + +### `square_list_refunds` + +List payment refunds, optionally filtered by location, status, and time range + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `locationId` | string | No | Filter refunds by location ID | +| `status` | string | No | Filter by refund status \(PENDING, COMPLETED, REJECTED, or FAILED\) | +| `beginTime` | string | No | RFC 3339 timestamp for the beginning of the reporting period | +| `endTime` | string | No | RFC 3339 timestamp for the end of the reporting period | +| `limit` | number | No | Maximum number of results to return per page | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `refunds` | array | Array of refund objects | +| ↳ `id` | string | Unique ID for the refund | +| ↳ `status` | string | Refund status \(PENDING, COMPLETED, REJECTED, or FAILED\) | +| ↳ `amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `processing_fee` | array | Processing fees refunded | +| ↳ `payment_id` | string | ID of the payment being refunded | +| ↳ `order_id` | string | ID of the associated order | +| ↳ `location_id` | string | ID of the associated location | +| ↳ `reason` | string | Reason for the refund | +| ↳ `created_at` | string | Timestamp when the refund was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the refund was last updated \(RFC 3339\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_create_customer` + +Create a new customer profile in the Square customer directory + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `givenName` | string | No | First name of the customer | +| `familyName` | string | No | Last name of the customer | +| `companyName` | string | No | Business name of the customer | +| `emailAddress` | string | No | Email address of the customer | +| `phoneNumber` | string | No | Phone number of the customer | +| `note` | string | No | Note about the customer | +| `referenceId` | string | No | Optional external reference for the customer | +| `address` | json | No | Square address object for the customer | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `customer` | object | The created customer object | +| ↳ `id` | string | Unique ID for the customer | +| ↳ `given_name` | string | First name of the customer | +| ↳ `family_name` | string | Last name of the customer | +| ↳ `nickname` | string | Nickname of the customer | +| ↳ `company_name` | string | Business name of the customer | +| ↳ `email_address` | string | Email address of the customer | +| ↳ `phone_number` | string | Phone number of the customer | +| ↳ `address` | object | Physical address | +| ↳ `address_line_1` | string | First line of the address | +| ↳ `address_line_2` | string | Second line of the address | +| ↳ `address_line_3` | string | Third line of the address | +| ↳ `locality` | string | City or town | +| ↳ `sublocality` | string | Neighborhood or district | +| ↳ `administrative_district_level_1` | string | State, province, or region | +| ↳ `postal_code` | string | Postal or ZIP code | +| ↳ `country` | string | Two-letter ISO 3166-1 alpha-2 country code | +| ↳ `first_name` | string | First name of the addressee | +| ↳ `last_name` | string | Last name of the addressee | +| ↳ `birthday` | string | Birthday in YYYY-MM-DD or MM-DD format | +| ↳ `reference_id` | string | Optional external reference for the customer | +| ↳ `note` | string | Note about the customer | +| ↳ `creation_source` | string | How the customer profile was created | +| ↳ `preferences` | json | Customer communication preferences | +| ↳ `group_ids` | array | IDs of customer groups the customer belongs to | +| ↳ `segment_ids` | array | IDs of customer segments the customer belongs to | +| ↳ `version` | number | Optimistic concurrency version of the customer | +| ↳ `created_at` | string | Timestamp when the customer was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the customer was last updated \(RFC 3339\) | +| `metadata` | json | Customer summary metadata | +| ↳ `id` | string | Square customer ID | +| ↳ `email_address` | string | Customer email address | +| ↳ `given_name` | string | Customer first name | +| ↳ `family_name` | string | Customer last name | + +### `square_get_customer` + +Retrieve a single customer profile by its ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `customerId` | string | Yes | ID of the customer to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `customer` | object | The retrieved customer object | +| ↳ `id` | string | Unique ID for the customer | +| ↳ `given_name` | string | First name of the customer | +| ↳ `family_name` | string | Last name of the customer | +| ↳ `nickname` | string | Nickname of the customer | +| ↳ `company_name` | string | Business name of the customer | +| ↳ `email_address` | string | Email address of the customer | +| ↳ `phone_number` | string | Phone number of the customer | +| ↳ `address` | object | Physical address | +| ↳ `address_line_1` | string | First line of the address | +| ↳ `address_line_2` | string | Second line of the address | +| ↳ `address_line_3` | string | Third line of the address | +| ↳ `locality` | string | City or town | +| ↳ `sublocality` | string | Neighborhood or district | +| ↳ `administrative_district_level_1` | string | State, province, or region | +| ↳ `postal_code` | string | Postal or ZIP code | +| ↳ `country` | string | Two-letter ISO 3166-1 alpha-2 country code | +| ↳ `first_name` | string | First name of the addressee | +| ↳ `last_name` | string | Last name of the addressee | +| ↳ `birthday` | string | Birthday in YYYY-MM-DD or MM-DD format | +| ↳ `reference_id` | string | Optional external reference for the customer | +| ↳ `note` | string | Note about the customer | +| ↳ `creation_source` | string | How the customer profile was created | +| ↳ `preferences` | json | Customer communication preferences | +| ↳ `group_ids` | array | IDs of customer groups the customer belongs to | +| ↳ `segment_ids` | array | IDs of customer segments the customer belongs to | +| ↳ `version` | number | Optimistic concurrency version of the customer | +| ↳ `created_at` | string | Timestamp when the customer was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the customer was last updated \(RFC 3339\) | +| `metadata` | json | Customer summary metadata | +| ↳ `id` | string | Square customer ID | +| ↳ `email_address` | string | Customer email address | +| ↳ `given_name` | string | Customer first name | +| ↳ `family_name` | string | Customer last name | + +### `square_list_customers` + +List customer profiles in the Square customer directory + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `limit` | number | No | Maximum number of results to return per page \(max 100\) | +| `cursor` | string | No | Pagination cursor from a previous response | +| `sortField` | string | No | Field to sort by \(DEFAULT or CREATED_AT\) | +| `sortOrder` | string | No | Sort order \(ASC or DESC\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `customers` | array | Array of customer objects | +| ↳ `id` | string | Unique ID for the customer | +| ↳ `given_name` | string | First name of the customer | +| ↳ `family_name` | string | Last name of the customer | +| ↳ `nickname` | string | Nickname of the customer | +| ↳ `company_name` | string | Business name of the customer | +| ↳ `email_address` | string | Email address of the customer | +| ↳ `phone_number` | string | Phone number of the customer | +| ↳ `address` | object | Physical address | +| ↳ `address_line_1` | string | First line of the address | +| ↳ `address_line_2` | string | Second line of the address | +| ↳ `address_line_3` | string | Third line of the address | +| ↳ `locality` | string | City or town | +| ↳ `sublocality` | string | Neighborhood or district | +| ↳ `administrative_district_level_1` | string | State, province, or region | +| ↳ `postal_code` | string | Postal or ZIP code | +| ↳ `country` | string | Two-letter ISO 3166-1 alpha-2 country code | +| ↳ `first_name` | string | First name of the addressee | +| ↳ `last_name` | string | Last name of the addressee | +| ↳ `birthday` | string | Birthday in YYYY-MM-DD or MM-DD format | +| ↳ `reference_id` | string | Optional external reference for the customer | +| ↳ `note` | string | Note about the customer | +| ↳ `creation_source` | string | How the customer profile was created | +| ↳ `preferences` | json | Customer communication preferences | +| ↳ `group_ids` | array | IDs of customer groups the customer belongs to | +| ↳ `segment_ids` | array | IDs of customer segments the customer belongs to | +| ↳ `version` | number | Optimistic concurrency version of the customer | +| ↳ `created_at` | string | Timestamp when the customer was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the customer was last updated \(RFC 3339\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_search_customers` + +Search customer profiles using filters such as email, phone, or creation date + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `query` | json | No | Square customer query object with optional filter and sort \(e.g. \{"filter":\{"email_address":\{"exact":"a@b.com"\}\}\}\) | +| `limit` | number | No | Maximum number of results to return per page | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `customers` | array | Array of matching customer objects | +| ↳ `id` | string | Unique ID for the customer | +| ↳ `given_name` | string | First name of the customer | +| ↳ `family_name` | string | Last name of the customer | +| ↳ `nickname` | string | Nickname of the customer | +| ↳ `company_name` | string | Business name of the customer | +| ↳ `email_address` | string | Email address of the customer | +| ↳ `phone_number` | string | Phone number of the customer | +| ↳ `address` | object | Physical address | +| ↳ `address_line_1` | string | First line of the address | +| ↳ `address_line_2` | string | Second line of the address | +| ↳ `address_line_3` | string | Third line of the address | +| ↳ `locality` | string | City or town | +| ↳ `sublocality` | string | Neighborhood or district | +| ↳ `administrative_district_level_1` | string | State, province, or region | +| ↳ `postal_code` | string | Postal or ZIP code | +| ↳ `country` | string | Two-letter ISO 3166-1 alpha-2 country code | +| ↳ `first_name` | string | First name of the addressee | +| ↳ `last_name` | string | Last name of the addressee | +| ↳ `birthday` | string | Birthday in YYYY-MM-DD or MM-DD format | +| ↳ `reference_id` | string | Optional external reference for the customer | +| ↳ `note` | string | Note about the customer | +| ↳ `creation_source` | string | How the customer profile was created | +| ↳ `preferences` | json | Customer communication preferences | +| ↳ `group_ids` | array | IDs of customer groups the customer belongs to | +| ↳ `segment_ids` | array | IDs of customer segments the customer belongs to | +| ↳ `version` | number | Optimistic concurrency version of the customer | +| ↳ `created_at` | string | Timestamp when the customer was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the customer was last updated \(RFC 3339\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_update_customer` + +Update fields on an existing customer profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `customerId` | string | Yes | ID of the customer to update | +| `givenName` | string | No | First name of the customer | +| `familyName` | string | No | Last name of the customer | +| `companyName` | string | No | Business name of the customer | +| `emailAddress` | string | No | Email address of the customer | +| `phoneNumber` | string | No | Phone number of the customer | +| `note` | string | No | Note about the customer | +| `referenceId` | string | No | Optional external reference for the customer | +| `address` | json | No | Square address object for the customer | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `customer` | object | The updated customer object | +| ↳ `id` | string | Unique ID for the customer | +| ↳ `given_name` | string | First name of the customer | +| ↳ `family_name` | string | Last name of the customer | +| ↳ `nickname` | string | Nickname of the customer | +| ↳ `company_name` | string | Business name of the customer | +| ↳ `email_address` | string | Email address of the customer | +| ↳ `phone_number` | string | Phone number of the customer | +| ↳ `address` | object | Physical address | +| ↳ `address_line_1` | string | First line of the address | +| ↳ `address_line_2` | string | Second line of the address | +| ↳ `address_line_3` | string | Third line of the address | +| ↳ `locality` | string | City or town | +| ↳ `sublocality` | string | Neighborhood or district | +| ↳ `administrative_district_level_1` | string | State, province, or region | +| ↳ `postal_code` | string | Postal or ZIP code | +| ↳ `country` | string | Two-letter ISO 3166-1 alpha-2 country code | +| ↳ `first_name` | string | First name of the addressee | +| ↳ `last_name` | string | Last name of the addressee | +| ↳ `birthday` | string | Birthday in YYYY-MM-DD or MM-DD format | +| ↳ `reference_id` | string | Optional external reference for the customer | +| ↳ `note` | string | Note about the customer | +| ↳ `creation_source` | string | How the customer profile was created | +| ↳ `preferences` | json | Customer communication preferences | +| ↳ `group_ids` | array | IDs of customer groups the customer belongs to | +| ↳ `segment_ids` | array | IDs of customer segments the customer belongs to | +| ↳ `version` | number | Optimistic concurrency version of the customer | +| ↳ `created_at` | string | Timestamp when the customer was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the customer was last updated \(RFC 3339\) | +| `metadata` | json | Customer summary metadata | +| ↳ `id` | string | Square customer ID | +| ↳ `email_address` | string | Customer email address | +| ↳ `given_name` | string | Customer first name | +| ↳ `family_name` | string | Customer last name | + +### `square_delete_customer` + +Delete a customer profile from the Square customer directory + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `customerId` | string | Yes | ID of the customer to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `deleted` | boolean | Whether the customer was deleted | +| `id` | string | ID of the deleted customer | + +### `square_list_locations` + +List all locations associated with the Square account + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `locations` | array | Array of location objects | +| ↳ `id` | string | Unique ID for the location | +| ↳ `name` | string | Name of the location | +| ↳ `address` | object | Physical address | +| ↳ `address_line_1` | string | First line of the address | +| ↳ `address_line_2` | string | Second line of the address | +| ↳ `address_line_3` | string | Third line of the address | +| ↳ `locality` | string | City or town | +| ↳ `sublocality` | string | Neighborhood or district | +| ↳ `administrative_district_level_1` | string | State, province, or region | +| ↳ `postal_code` | string | Postal or ZIP code | +| ↳ `country` | string | Two-letter ISO 3166-1 alpha-2 country code | +| ↳ `first_name` | string | First name of the addressee | +| ↳ `last_name` | string | Last name of the addressee | +| ↳ `timezone` | string | IANA timezone of the location | +| ↳ `status` | string | Location status \(ACTIVE or INACTIVE\) | +| ↳ `type` | string | Location type \(PHYSICAL or MOBILE\) | +| ↳ `merchant_id` | string | ID of the merchant that owns the location | +| ↳ `country` | string | Country code of the location | +| ↳ `language_code` | string | Language code of the location | +| ↳ `currency` | string | Currency used by the location | +| ↳ `phone_number` | string | Phone number of the location | +| ↳ `business_name` | string | Business name shown to customers | +| ↳ `business_email` | string | Email of the business | +| ↳ `description` | string | Description of the location | +| ↳ `capabilities` | array | Capabilities of the location \(e.g. CREDIT_CARD_PROCESSING\) | +| ↳ `created_at` | string | Timestamp when the location was created \(RFC 3339\) | +| `metadata` | json | List metadata | +| ↳ `count` | number | Number of locations returned | + +### `square_get_location` + +Retrieve a single location by its ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `locationId` | string | Yes | ID of the location to retrieve \(use "main" for the main location\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `location` | object | The retrieved location object | +| ↳ `id` | string | Unique ID for the location | +| ↳ `name` | string | Name of the location | +| ↳ `address` | object | Physical address | +| ↳ `address_line_1` | string | First line of the address | +| ↳ `address_line_2` | string | Second line of the address | +| ↳ `address_line_3` | string | Third line of the address | +| ↳ `locality` | string | City or town | +| ↳ `sublocality` | string | Neighborhood or district | +| ↳ `administrative_district_level_1` | string | State, province, or region | +| ↳ `postal_code` | string | Postal or ZIP code | +| ↳ `country` | string | Two-letter ISO 3166-1 alpha-2 country code | +| ↳ `first_name` | string | First name of the addressee | +| ↳ `last_name` | string | Last name of the addressee | +| ↳ `timezone` | string | IANA timezone of the location | +| ↳ `status` | string | Location status \(ACTIVE or INACTIVE\) | +| ↳ `type` | string | Location type \(PHYSICAL or MOBILE\) | +| ↳ `merchant_id` | string | ID of the merchant that owns the location | +| ↳ `country` | string | Country code of the location | +| ↳ `language_code` | string | Language code of the location | +| ↳ `currency` | string | Currency used by the location | +| ↳ `phone_number` | string | Phone number of the location | +| ↳ `business_name` | string | Business name shown to customers | +| ↳ `business_email` | string | Email of the business | +| ↳ `description` | string | Description of the location | +| ↳ `capabilities` | array | Capabilities of the location \(e.g. CREDIT_CARD_PROCESSING\) | +| ↳ `created_at` | string | Timestamp when the location was created \(RFC 3339\) | +| `metadata` | json | Location summary metadata | +| ↳ `id` | string | Square location ID | +| ↳ `name` | string | Location name | + +### `square_create_order` + +Create an order with line items, taxes, discounts, and fulfillments + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `order` | json | Yes | Square order object including location_id and line_items \(e.g. \{"location_id":"L1","line_items":\[\{"name":"Coffee","quantity":"1","base_price_money":\{"amount":250,"currency":"USD"\}\}\]\}\) | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `order` | object | The created order object | +| ↳ `id` | string | Unique ID for the order | +| ↳ `location_id` | string | ID of the location for the order | +| ↳ `reference_id` | string | Optional external reference for the order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `state` | string | Order state \(OPEN, COMPLETED, or CANCELED\) | +| ↳ `version` | number | Optimistic concurrency version of the order | +| ↳ `line_items` | array | Line items in the order | +| ↳ `taxes` | array | Taxes applied to the order | +| ↳ `discounts` | array | Discounts applied to the order | +| ↳ `fulfillments` | array | Fulfillments for the order | +| ↳ `net_amounts` | json | Net money amounts for the order | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tax_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_discount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_service_charge_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `created_at` | string | Timestamp when the order was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the order was last updated \(RFC 3339\) | +| ↳ `closed_at` | string | Timestamp when the order was closed \(RFC 3339\) | +| `metadata` | json | Order summary metadata | +| ↳ `id` | string | Square order ID | +| ↳ `state` | string | Current order state | +| ↳ `location_id` | string | Order location ID | + +### `square_get_order` + +Retrieve a single order by its ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `orderId` | string | Yes | ID of the order to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `order` | object | The retrieved order object | +| ↳ `id` | string | Unique ID for the order | +| ↳ `location_id` | string | ID of the location for the order | +| ↳ `reference_id` | string | Optional external reference for the order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `state` | string | Order state \(OPEN, COMPLETED, or CANCELED\) | +| ↳ `version` | number | Optimistic concurrency version of the order | +| ↳ `line_items` | array | Line items in the order | +| ↳ `taxes` | array | Taxes applied to the order | +| ↳ `discounts` | array | Discounts applied to the order | +| ↳ `fulfillments` | array | Fulfillments for the order | +| ↳ `net_amounts` | json | Net money amounts for the order | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tax_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_discount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_service_charge_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `created_at` | string | Timestamp when the order was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the order was last updated \(RFC 3339\) | +| ↳ `closed_at` | string | Timestamp when the order was closed \(RFC 3339\) | +| `metadata` | json | Order summary metadata | +| ↳ `id` | string | Square order ID | +| ↳ `state` | string | Current order state | +| ↳ `location_id` | string | Order location ID | + +### `square_search_orders` + +Search orders across one or more locations using filters and sorting + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `locationIds` | array | Yes | Array of location IDs to search within | +| `query` | json | No | Square order query object with optional filter and sort \(e.g. \{"filter":\{"state_filter":\{"states":\["OPEN"\]\}\}\}\) | +| `limit` | number | No | Maximum number of results to return per page | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `orders` | array | Array of matching order objects | +| ↳ `id` | string | Unique ID for the order | +| ↳ `location_id` | string | ID of the location for the order | +| ↳ `reference_id` | string | Optional external reference for the order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `state` | string | Order state \(OPEN, COMPLETED, or CANCELED\) | +| ↳ `version` | number | Optimistic concurrency version of the order | +| ↳ `line_items` | array | Line items in the order | +| ↳ `taxes` | array | Taxes applied to the order | +| ↳ `discounts` | array | Discounts applied to the order | +| ↳ `fulfillments` | array | Fulfillments for the order | +| ↳ `net_amounts` | json | Net money amounts for the order | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tax_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_discount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_service_charge_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `created_at` | string | Timestamp when the order was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the order was last updated \(RFC 3339\) | +| ↳ `closed_at` | string | Timestamp when the order was closed \(RFC 3339\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_pay_order` + +Pay for an order using one or more already-approved payments + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `orderId` | string | Yes | ID of the order to pay for | +| `paymentIds` | array | No | IDs of approved payments to apply to the order | +| `orderVersion` | number | No | Version of the order being paid \(for optimistic concurrency\) | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `order` | object | The paid order object | +| ↳ `id` | string | Unique ID for the order | +| ↳ `location_id` | string | ID of the location for the order | +| ↳ `reference_id` | string | Optional external reference for the order | +| ↳ `customer_id` | string | ID of the associated customer | +| ↳ `state` | string | Order state \(OPEN, COMPLETED, or CANCELED\) | +| ↳ `version` | number | Optimistic concurrency version of the order | +| ↳ `line_items` | array | Line items in the order | +| ↳ `taxes` | array | Taxes applied to the order | +| ↳ `discounts` | array | Discounts applied to the order | +| ↳ `fulfillments` | array | Fulfillments for the order | +| ↳ `net_amounts` | json | Net money amounts for the order | +| ↳ `total_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tax_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_discount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_service_charge_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `total_tip_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `created_at` | string | Timestamp when the order was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the order was last updated \(RFC 3339\) | +| ↳ `closed_at` | string | Timestamp when the order was closed \(RFC 3339\) | +| `metadata` | json | Order summary metadata | +| ↳ `id` | string | Square order ID | +| ↳ `state` | string | Current order state | +| ↳ `location_id` | string | Order location ID | + +### `square_create_invoice` + +Create a draft invoice for an existing order and customer + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `invoice` | json | Yes | Square invoice object including location_id, order_id, primary_recipient, and payment_requests \(e.g. \{"location_id":"L1","order_id":"O1","primary_recipient":\{"customer_id":"C1"\},"payment_requests":\[\{"request_type":"BALANCE","due_date":"2026-07-01"\}\]\}\) | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `invoice` | object | The created invoice object | +| ↳ `id` | string | Unique ID for the invoice | +| ↳ `version` | number | Optimistic concurrency version of the invoice | +| ↳ `location_id` | string | ID of the location for the invoice | +| ↳ `order_id` | string | ID of the order the invoice bills for | +| ↳ `status` | string | Invoice status \(DRAFT, UNPAID, SCHEDULED, PARTIALLY_PAID, PAID, etc.\) | +| ↳ `invoice_number` | string | Human-readable invoice number | +| ↳ `title` | string | Title of the invoice | +| ↳ `description` | string | Description of the invoice | +| ↳ `public_url` | string | URL where the customer can view and pay the invoice | +| ↳ `primary_recipient` | json | Primary recipient of the invoice | +| ↳ `payment_requests` | array | Payment requests for the invoice | +| ↳ `next_payment_amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `scheduled_at` | string | Timestamp when the invoice is scheduled to be sent \(RFC 3339\) | +| ↳ `timezone` | string | Timezone used for invoice dates | +| ↳ `delivery_method` | string | How the invoice is delivered \(EMAIL, SHARE_MANUALLY, SMS\) | +| ↳ `created_at` | string | Timestamp when the invoice was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the invoice was last updated \(RFC 3339\) | +| `metadata` | json | Invoice summary metadata | +| ↳ `id` | string | Square invoice ID | +| ↳ `status` | string | Current invoice status | +| ↳ `version` | number | Invoice version | + +### `square_get_invoice` + +Retrieve a single invoice by its ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `invoiceId` | string | Yes | ID of the invoice to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `invoice` | object | The retrieved invoice object | +| ↳ `id` | string | Unique ID for the invoice | +| ↳ `version` | number | Optimistic concurrency version of the invoice | +| ↳ `location_id` | string | ID of the location for the invoice | +| ↳ `order_id` | string | ID of the order the invoice bills for | +| ↳ `status` | string | Invoice status \(DRAFT, UNPAID, SCHEDULED, PARTIALLY_PAID, PAID, etc.\) | +| ↳ `invoice_number` | string | Human-readable invoice number | +| ↳ `title` | string | Title of the invoice | +| ↳ `description` | string | Description of the invoice | +| ↳ `public_url` | string | URL where the customer can view and pay the invoice | +| ↳ `primary_recipient` | json | Primary recipient of the invoice | +| ↳ `payment_requests` | array | Payment requests for the invoice | +| ↳ `next_payment_amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `scheduled_at` | string | Timestamp when the invoice is scheduled to be sent \(RFC 3339\) | +| ↳ `timezone` | string | Timezone used for invoice dates | +| ↳ `delivery_method` | string | How the invoice is delivered \(EMAIL, SHARE_MANUALLY, SMS\) | +| ↳ `created_at` | string | Timestamp when the invoice was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the invoice was last updated \(RFC 3339\) | +| `metadata` | json | Invoice summary metadata | +| ↳ `id` | string | Square invoice ID | +| ↳ `status` | string | Current invoice status | +| ↳ `version` | number | Invoice version | + +### `square_list_invoices` + +List invoices for a specific location + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `locationId` | string | Yes | ID of the location to list invoices for | +| `limit` | number | No | Maximum number of results to return per page | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `invoices` | array | Array of invoice objects | +| ↳ `id` | string | Unique ID for the invoice | +| ↳ `version` | number | Optimistic concurrency version of the invoice | +| ↳ `location_id` | string | ID of the location for the invoice | +| ↳ `order_id` | string | ID of the order the invoice bills for | +| ↳ `status` | string | Invoice status \(DRAFT, UNPAID, SCHEDULED, PARTIALLY_PAID, PAID, etc.\) | +| ↳ `invoice_number` | string | Human-readable invoice number | +| ↳ `title` | string | Title of the invoice | +| ↳ `description` | string | Description of the invoice | +| ↳ `public_url` | string | URL where the customer can view and pay the invoice | +| ↳ `primary_recipient` | json | Primary recipient of the invoice | +| ↳ `payment_requests` | array | Payment requests for the invoice | +| ↳ `next_payment_amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `scheduled_at` | string | Timestamp when the invoice is scheduled to be sent \(RFC 3339\) | +| ↳ `timezone` | string | Timezone used for invoice dates | +| ↳ `delivery_method` | string | How the invoice is delivered \(EMAIL, SHARE_MANUALLY, SMS\) | +| ↳ `created_at` | string | Timestamp when the invoice was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the invoice was last updated \(RFC 3339\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_search_invoices` + +Search invoices across one or more locations + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `locationIds` | array | Yes | Array of location IDs to search within | +| `limit` | number | No | Maximum number of results to return per page | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `invoices` | array | Array of matching invoice objects | +| ↳ `id` | string | Unique ID for the invoice | +| ↳ `version` | number | Optimistic concurrency version of the invoice | +| ↳ `location_id` | string | ID of the location for the invoice | +| ↳ `order_id` | string | ID of the order the invoice bills for | +| ↳ `status` | string | Invoice status \(DRAFT, UNPAID, SCHEDULED, PARTIALLY_PAID, PAID, etc.\) | +| ↳ `invoice_number` | string | Human-readable invoice number | +| ↳ `title` | string | Title of the invoice | +| ↳ `description` | string | Description of the invoice | +| ↳ `public_url` | string | URL where the customer can view and pay the invoice | +| ↳ `primary_recipient` | json | Primary recipient of the invoice | +| ↳ `payment_requests` | array | Payment requests for the invoice | +| ↳ `next_payment_amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `scheduled_at` | string | Timestamp when the invoice is scheduled to be sent \(RFC 3339\) | +| ↳ `timezone` | string | Timezone used for invoice dates | +| ↳ `delivery_method` | string | How the invoice is delivered \(EMAIL, SHARE_MANUALLY, SMS\) | +| ↳ `created_at` | string | Timestamp when the invoice was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the invoice was last updated \(RFC 3339\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_publish_invoice` + +Publish a draft invoice so it is sent to the customer and becomes payable + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `invoiceId` | string | Yes | ID of the invoice to publish | +| `version` | number | Yes | Current version of the invoice \(use the version returned by Create Invoice\) | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `invoice` | object | The published invoice object | +| ↳ `id` | string | Unique ID for the invoice | +| ↳ `version` | number | Optimistic concurrency version of the invoice | +| ↳ `location_id` | string | ID of the location for the invoice | +| ↳ `order_id` | string | ID of the order the invoice bills for | +| ↳ `status` | string | Invoice status \(DRAFT, UNPAID, SCHEDULED, PARTIALLY_PAID, PAID, etc.\) | +| ↳ `invoice_number` | string | Human-readable invoice number | +| ↳ `title` | string | Title of the invoice | +| ↳ `description` | string | Description of the invoice | +| ↳ `public_url` | string | URL where the customer can view and pay the invoice | +| ↳ `primary_recipient` | json | Primary recipient of the invoice | +| ↳ `payment_requests` | array | Payment requests for the invoice | +| ↳ `next_payment_amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `scheduled_at` | string | Timestamp when the invoice is scheduled to be sent \(RFC 3339\) | +| ↳ `timezone` | string | Timezone used for invoice dates | +| ↳ `delivery_method` | string | How the invoice is delivered \(EMAIL, SHARE_MANUALLY, SMS\) | +| ↳ `created_at` | string | Timestamp when the invoice was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the invoice was last updated \(RFC 3339\) | +| `metadata` | json | Invoice summary metadata | +| ↳ `id` | string | Square invoice ID | +| ↳ `status` | string | Current invoice status | +| ↳ `version` | number | Invoice version | + +### `square_cancel_invoice` + +Cancel a published invoice that is unpaid or partially paid + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `invoiceId` | string | Yes | ID of the invoice to cancel | +| `version` | number | Yes | Current version of the invoice | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `invoice` | object | The canceled invoice object | +| ↳ `id` | string | Unique ID for the invoice | +| ↳ `version` | number | Optimistic concurrency version of the invoice | +| ↳ `location_id` | string | ID of the location for the invoice | +| ↳ `order_id` | string | ID of the order the invoice bills for | +| ↳ `status` | string | Invoice status \(DRAFT, UNPAID, SCHEDULED, PARTIALLY_PAID, PAID, etc.\) | +| ↳ `invoice_number` | string | Human-readable invoice number | +| ↳ `title` | string | Title of the invoice | +| ↳ `description` | string | Description of the invoice | +| ↳ `public_url` | string | URL where the customer can view and pay the invoice | +| ↳ `primary_recipient` | json | Primary recipient of the invoice | +| ↳ `payment_requests` | array | Payment requests for the invoice | +| ↳ `next_payment_amount_money` | object | Monetary amount with a currency | +| ↳ `amount` | number | Amount in the smallest denomination of the currency \(e.g. cents for USD\) | +| ↳ `currency` | string | Three-letter ISO 4217 currency code \(e.g. USD\) | +| ↳ `scheduled_at` | string | Timestamp when the invoice is scheduled to be sent \(RFC 3339\) | +| ↳ `timezone` | string | Timezone used for invoice dates | +| ↳ `delivery_method` | string | How the invoice is delivered \(EMAIL, SHARE_MANUALLY, SMS\) | +| ↳ `created_at` | string | Timestamp when the invoice was created \(RFC 3339\) | +| ↳ `updated_at` | string | Timestamp when the invoice was last updated \(RFC 3339\) | +| `metadata` | json | Invoice summary metadata | +| ↳ `id` | string | Square invoice ID | +| ↳ `status` | string | Current invoice status | +| ↳ `version` | number | Invoice version | + +### `square_delete_invoice` + +Delete a draft invoice + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `invoiceId` | string | Yes | ID of the draft invoice to delete | +| `version` | number | No | Current version of the invoice \(required if the invoice has been updated\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `deleted` | boolean | Whether the invoice was deleted | +| `id` | string | ID of the deleted invoice | + +### `square_upsert_catalog_object` + +Create or update a catalog object such as an item, variation, or category + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `object` | json | Yes | Square catalog object to create or update. Use ID "#name" for new objects \(e.g. \{"type":"ITEM","id":"#Coffee","item_data":\{"name":"Coffee"\}\}\) | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `object` | object | The created or updated catalog object | +| ↳ `type` | string | Type of catalog object \(ITEM, ITEM_VARIATION, CATEGORY, IMAGE, etc.\) | +| ↳ `id` | string | Unique ID for the catalog object | +| ↳ `version` | number | Optimistic concurrency version of the object | +| ↳ `updated_at` | string | Timestamp when the object was last updated \(RFC 3339\) | +| ↳ `is_deleted` | boolean | Whether the object is deleted | +| ↳ `present_at_all_locations` | boolean | Whether the object is present at all locations | +| ↳ `item_data` | json | Item-specific data \(when type is ITEM\) | +| ↳ `item_variation_data` | json | Variation-specific data \(when type is ITEM_VARIATION\) | +| ↳ `category_data` | json | Category-specific data \(when type is CATEGORY\) | +| ↳ `image_data` | json | Image-specific data \(when type is IMAGE\) | +| `metadata` | json | Catalog object summary metadata | +| ↳ `id` | string | Square catalog object ID | +| ↳ `type` | string | Catalog object type | +| ↳ `version` | number | Catalog object version | + +### `square_get_catalog_object` + +Retrieve a single catalog object by its ID + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `objectId` | string | Yes | ID of the catalog object to retrieve | +| `includeRelatedObjects` | boolean | No | Whether to include related objects such as an item variations | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `object` | object | The retrieved catalog object | +| ↳ `type` | string | Type of catalog object \(ITEM, ITEM_VARIATION, CATEGORY, IMAGE, etc.\) | +| ↳ `id` | string | Unique ID for the catalog object | +| ↳ `version` | number | Optimistic concurrency version of the object | +| ↳ `updated_at` | string | Timestamp when the object was last updated \(RFC 3339\) | +| ↳ `is_deleted` | boolean | Whether the object is deleted | +| ↳ `present_at_all_locations` | boolean | Whether the object is present at all locations | +| ↳ `item_data` | json | Item-specific data \(when type is ITEM\) | +| ↳ `item_variation_data` | json | Variation-specific data \(when type is ITEM_VARIATION\) | +| ↳ `category_data` | json | Category-specific data \(when type is CATEGORY\) | +| ↳ `image_data` | json | Image-specific data \(when type is IMAGE\) | +| `metadata` | json | Catalog object summary metadata | +| ↳ `id` | string | Square catalog object ID | +| ↳ `type` | string | Catalog object type | +| ↳ `version` | number | Catalog object version | + +### `square_list_catalog` + +List catalog objects, optionally filtered by type + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `types` | string | No | Comma-separated catalog object types to return \(e.g. ITEM,CATEGORY\). Defaults to all top-level types | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `objects` | array | Array of catalog objects | +| ↳ `type` | string | Type of catalog object \(ITEM, ITEM_VARIATION, CATEGORY, IMAGE, etc.\) | +| ↳ `id` | string | Unique ID for the catalog object | +| ↳ `version` | number | Optimistic concurrency version of the object | +| ↳ `updated_at` | string | Timestamp when the object was last updated \(RFC 3339\) | +| ↳ `is_deleted` | boolean | Whether the object is deleted | +| ↳ `present_at_all_locations` | boolean | Whether the object is present at all locations | +| ↳ `item_data` | json | Item-specific data \(when type is ITEM\) | +| ↳ `item_variation_data` | json | Variation-specific data \(when type is ITEM_VARIATION\) | +| ↳ `category_data` | json | Category-specific data \(when type is CATEGORY\) | +| ↳ `image_data` | json | Image-specific data \(when type is IMAGE\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_search_catalog_objects` + +Search catalog objects by type and query filters + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `objectTypes` | array | No | Array of catalog object types to search \(e.g. \["ITEM","CATEGORY"\]\) | +| `query` | json | No | Square catalog query object \(e.g. \{"text_query":\{"keywords":\["coffee"\]\}\} or \{"prefix_query":\{...\}\}\) | +| `limit` | number | No | Maximum number of results to return per page | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `objects` | array | Array of matching catalog objects | +| ↳ `type` | string | Type of catalog object \(ITEM, ITEM_VARIATION, CATEGORY, IMAGE, etc.\) | +| ↳ `id` | string | Unique ID for the catalog object | +| ↳ `version` | number | Optimistic concurrency version of the object | +| ↳ `updated_at` | string | Timestamp when the object was last updated \(RFC 3339\) | +| ↳ `is_deleted` | boolean | Whether the object is deleted | +| ↳ `present_at_all_locations` | boolean | Whether the object is present at all locations | +| ↳ `item_data` | json | Item-specific data \(when type is ITEM\) | +| ↳ `item_variation_data` | json | Variation-specific data \(when type is ITEM_VARIATION\) | +| ↳ `category_data` | json | Category-specific data \(when type is CATEGORY\) | +| ↳ `image_data` | json | Image-specific data \(when type is IMAGE\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + +### `square_create_catalog_image` + +Upload an image and attach it to the catalog, optionally to a specific item + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `file` | file | No | The image file to upload \(UserFile object\) | +| `fileContent` | string | No | Legacy: base64 encoded image content | +| `fileName` | string | No | Optional filename override for the image | +| `objectId` | string | No | ID of the catalog object \(e.g. an item\) to attach the image to | +| `caption` | string | No | Caption \(alt text\) for the image | +| `idempotencyKey` | string | No | Unique key to make the request idempotent \(auto-generated if omitted\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `object` | object | The created catalog image object | +| ↳ `type` | string | Type of catalog object \(ITEM, ITEM_VARIATION, CATEGORY, IMAGE, etc.\) | +| ↳ `id` | string | Unique ID for the catalog object | +| ↳ `version` | number | Optimistic concurrency version of the object | +| ↳ `updated_at` | string | Timestamp when the object was last updated \(RFC 3339\) | +| ↳ `is_deleted` | boolean | Whether the object is deleted | +| ↳ `present_at_all_locations` | boolean | Whether the object is present at all locations | +| ↳ `item_data` | json | Item-specific data \(when type is ITEM\) | +| ↳ `item_variation_data` | json | Variation-specific data \(when type is ITEM_VARIATION\) | +| ↳ `category_data` | json | Category-specific data \(when type is CATEGORY\) | +| ↳ `image_data` | json | Image-specific data \(when type is IMAGE\) | +| `metadata` | json | Catalog object summary metadata | +| ↳ `id` | string | Square catalog object ID | +| ↳ `type` | string | Catalog object type | +| ↳ `version` | number | Catalog object version | + +### `square_delete_catalog_object` + +Delete a catalog object and its children (e.g. an item and its variations) + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `objectId` | string | Yes | ID of the catalog object to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `deleted` | boolean | Whether the catalog object was deleted | +| `deleted_object_ids` | array | IDs of all catalog objects deleted \(including children\) | +| `deleted_at` | string | Timestamp when the deletion occurred \(RFC 3339\) | + +### `square_batch_retrieve_inventory_counts` + +Retrieve current inventory counts for catalog items across locations + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Square access token \(personal access token\) | +| `catalogObjectIds` | array | No | IDs of the catalog item variations to retrieve counts for | +| `locationIds` | array | No | IDs of the locations to retrieve counts for \(defaults to all locations\) | +| `cursor` | string | No | Pagination cursor from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `counts` | array | Array of inventory count objects | +| ↳ `catalog_object_id` | string | ID of the catalog object \(item variation\) being counted | +| ↳ `catalog_object_type` | string | Type of the counted catalog object \(usually ITEM_VARIATION\) | +| ↳ `state` | string | Inventory state \(e.g. IN_STOCK, SOLD, WASTE\) | +| ↳ `location_id` | string | ID of the location for this count | +| ↳ `quantity` | string | Number of units in the given state at the location | +| ↳ `calculated_at` | string | Timestamp when the count was calculated \(RFC 3339\) | +| `metadata` | json | List pagination metadata | +| ↳ `count` | number | Number of items returned in this page | +| ↳ `cursor` | string | Pagination cursor to fetch the next page, if more results exist | + + diff --git a/apps/sim/app/api/tools/square/catalog-image/route.ts b/apps/sim/app/api/tools/square/catalog-image/route.ts new file mode 100644 index 00000000000..fa35366cf48 --- /dev/null +++ b/apps/sim/app/api/tools/square/catalog-image/route.ts @@ -0,0 +1,121 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { squareCatalogImageContract } from '@/lib/api/contracts/tools/square' +import { parseRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { generateRequestId } from '@/lib/core/utils/request' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { processFilesToUserFiles, type RawFileInput } from '@/lib/uploads/utils/file-utils' +import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server' +import { assertToolFileAccess } from '@/app/api/files/authorization' +import { SQUARE_API_VERSION, SQUARE_BASE_URL } from '@/tools/square/types' + +export const dynamic = 'force-dynamic' + +const logger = createLogger('SquareCatalogImageAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateRequestId() + + try { + const authResult = await checkInternalAuth(request, { requireWorkflowId: false }) + + if (!authResult.success || !authResult.userId) { + logger.warn(`[${requestId}] Unauthorized Square catalog image upload: ${authResult.error}`) + return NextResponse.json( + { success: false, error: authResult.error || 'Authentication required' }, + { status: 401 } + ) + } + + const parsed = await parseRequest(squareCatalogImageContract, request, {}) + if (!parsed.success) return parsed.response + const validatedData = parsed.data.body + + let fileBuffer: Buffer + let fileName: string + let mimeType = 'application/octet-stream' + + if (validatedData.file) { + const userFiles = processFilesToUserFiles( + [validatedData.file as RawFileInput], + requestId, + logger + ) + + if (userFiles.length === 0) { + return NextResponse.json({ success: false, error: 'Invalid file input' }, { status: 400 }) + } + + const userFile = userFiles[0] + const denied = await assertToolFileAccess(userFile.key, authResult.userId, requestId, logger) + if (denied) return denied + + fileBuffer = await downloadFileFromStorage(userFile, requestId, logger) + fileName = validatedData.fileName || userFile.name + if (userFile.type) mimeType = userFile.type + } else if (validatedData.fileContent) { + fileBuffer = Buffer.from(validatedData.fileContent, 'base64') + fileName = validatedData.fileName || 'image' + } else { + return NextResponse.json({ success: false, error: 'File is required' }, { status: 400 }) + } + + const imageRequest: Record = { + idempotency_key: validatedData.idempotencyKey || generateId(), + image: { + type: 'IMAGE', + id: '#square_catalog_image', + image_data: validatedData.caption ? { caption: validatedData.caption } : {}, + }, + } + if (validatedData.objectId) imageRequest.object_id = validatedData.objectId + + const formData = new FormData() + formData.append('request', JSON.stringify(imageRequest)) + formData.append( + 'image_file', + new Blob([new Uint8Array(fileBuffer)], { type: mimeType }), + fileName + ) + + const response = await fetch(`${SQUARE_BASE_URL}/v2/catalog/images`, { + method: 'POST', + headers: { + Authorization: `Bearer ${validatedData.accessToken}`, + 'Square-Version': SQUARE_API_VERSION, + }, + body: formData, + }) + + const data = await response.json() + + if (!response.ok) { + const errorMessage = data?.errors?.[0]?.detail || 'Failed to upload catalog image' + logger.error(`[${requestId}] Square API error:`, { status: response.status, data }) + return NextResponse.json({ success: false, error: errorMessage }, { status: response.status }) + } + + const object = data.image ?? {} + + return NextResponse.json({ + success: true, + output: { + object, + metadata: { + id: object.id ?? '', + type: object.type ?? null, + version: object.version ?? null, + }, + }, + }) + } catch (error) { + logger.error(`[${requestId}] Unexpected error:`, error) + return NextResponse.json( + { success: false, error: getErrorMessage(error, 'Unknown error') }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/blocks/blocks/square.ts b/apps/sim/blocks/blocks/square.ts new file mode 100644 index 00000000000..ac134f30cb2 --- /dev/null +++ b/apps/sim/blocks/blocks/square.ts @@ -0,0 +1,877 @@ +import { SquareIcon } from '@/components/icons' +import type { BlockConfig, BlockMeta } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' +import { normalizeFileInput } from '@/blocks/utils' +import type { SquareResponse } from '@/tools/square/types' + +export const SquareBlock: BlockConfig = { + type: 'square', + name: 'Square', + description: 'Process payments and manage Square commerce data', + authMode: AuthMode.ApiKey, + longDescription: + 'Integrate Square into the workflow. Take and refund payments, manage customers, build catalog items and images, create and search orders, and issue invoices. Authenticate with a Square access token (personal access token).', + docsLink: 'https://docs.sim.ai/integrations/square', + category: 'tools', + integrationType: IntegrationType.Commerce, + bgColor: '#000000', + icon: SquareIcon, + + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + // Payments + { label: 'Create Payment', id: 'create_payment' }, + { label: 'Get Payment', id: 'get_payment' }, + { label: 'List Payments', id: 'list_payments' }, + { label: 'Cancel Payment', id: 'cancel_payment' }, + { label: 'Complete Payment', id: 'complete_payment' }, + // Refunds + { label: 'Refund Payment', id: 'refund_payment' }, + { label: 'Get Refund', id: 'get_refund' }, + { label: 'List Refunds', id: 'list_refunds' }, + // Customers + { label: 'Create Customer', id: 'create_customer' }, + { label: 'Get Customer', id: 'get_customer' }, + { label: 'List Customers', id: 'list_customers' }, + { label: 'Search Customers', id: 'search_customers' }, + { label: 'Update Customer', id: 'update_customer' }, + { label: 'Delete Customer', id: 'delete_customer' }, + // Locations + { label: 'List Locations', id: 'list_locations' }, + { label: 'Get Location', id: 'get_location' }, + // Orders + { label: 'Create Order', id: 'create_order' }, + { label: 'Get Order', id: 'get_order' }, + { label: 'Search Orders', id: 'search_orders' }, + { label: 'Pay Order', id: 'pay_order' }, + // Invoices + { label: 'Create Invoice', id: 'create_invoice' }, + { label: 'Get Invoice', id: 'get_invoice' }, + { label: 'List Invoices', id: 'list_invoices' }, + { label: 'Search Invoices', id: 'search_invoices' }, + { label: 'Publish Invoice', id: 'publish_invoice' }, + { label: 'Cancel Invoice', id: 'cancel_invoice' }, + { label: 'Delete Invoice', id: 'delete_invoice' }, + // Catalog + { label: 'Upsert Catalog Object', id: 'upsert_catalog_object' }, + { label: 'Get Catalog Object', id: 'get_catalog_object' }, + { label: 'List Catalog', id: 'list_catalog' }, + { label: 'Search Catalog Objects', id: 'search_catalog_objects' }, + { label: 'Create Catalog Image', id: 'create_catalog_image' }, + { label: 'Delete Catalog Object', id: 'delete_catalog_object' }, + // Inventory + { label: 'Batch Retrieve Inventory Counts', id: 'batch_retrieve_inventory_counts' }, + ], + value: () => 'create_payment', + }, + { + id: 'apiKey', + title: 'Square Access Token', + type: 'short-input', + password: true, + placeholder: 'Enter your Square access token', + required: true, + }, + + // Payments + { + id: 'sourceId', + title: 'Source ID', + type: 'short-input', + placeholder: 'Card nonce, card-on-file ID, or wallet token', + condition: { field: 'operation', value: 'create_payment' }, + required: { field: 'operation', value: 'create_payment' }, + }, + { + id: 'paymentId', + title: 'Payment ID', + type: 'short-input', + placeholder: 'Square payment ID', + condition: { + field: 'operation', + value: ['get_payment', 'refund_payment', 'cancel_payment', 'complete_payment'], + }, + required: { + field: 'operation', + value: ['get_payment', 'refund_payment', 'cancel_payment', 'complete_payment'], + }, + }, + { + id: 'refundId', + title: 'Refund ID', + type: 'short-input', + placeholder: 'Square refund ID', + condition: { field: 'operation', value: 'get_refund' }, + required: { field: 'operation', value: 'get_refund' }, + }, + { + id: 'status', + title: 'Status', + type: 'short-input', + placeholder: 'Filter by status (e.g. COMPLETED)', + condition: { field: 'operation', value: 'list_refunds' }, + mode: 'advanced', + }, + { + id: 'amount', + title: 'Amount', + type: 'short-input', + placeholder: 'Smallest denomination (e.g. 1000 for $10.00)', + condition: { field: 'operation', value: ['create_payment', 'refund_payment'] }, + required: { field: 'operation', value: ['create_payment', 'refund_payment'] }, + }, + { + id: 'currency', + title: 'Currency', + type: 'short-input', + placeholder: 'ISO 4217 code (e.g. USD)', + condition: { field: 'operation', value: ['create_payment', 'refund_payment'] }, + required: { field: 'operation', value: ['create_payment', 'refund_payment'] }, + }, + { + id: 'reason', + title: 'Refund Reason', + type: 'short-input', + placeholder: 'Reason for the refund', + condition: { field: 'operation', value: 'refund_payment' }, + }, + { + id: 'autocomplete', + title: 'Capture Immediately', + type: 'dropdown', + options: [ + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + condition: { field: 'operation', value: 'create_payment' }, + mode: 'advanced', + }, + { + id: 'beginTime', + title: 'Begin Time', + type: 'short-input', + placeholder: 'RFC 3339 timestamp', + condition: { field: 'operation', value: ['list_payments', 'list_refunds'] }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: 'Generate an RFC 3339 timestamp. Return ONLY the timestamp string.', + generationType: 'timestamp', + }, + }, + { + id: 'endTime', + title: 'End Time', + type: 'short-input', + placeholder: 'RFC 3339 timestamp', + condition: { field: 'operation', value: ['list_payments', 'list_refunds'] }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: 'Generate an RFC 3339 timestamp. Return ONLY the timestamp string.', + generationType: 'timestamp', + }, + }, + + // Customers + { + id: 'customerId', + title: 'Customer ID', + type: 'short-input', + placeholder: 'Square customer ID', + condition: { + field: 'operation', + value: ['create_payment', 'get_customer', 'update_customer', 'delete_customer'], + }, + required: { + field: 'operation', + value: ['get_customer', 'update_customer', 'delete_customer'], + }, + }, + { + id: 'givenName', + title: 'First Name', + type: 'short-input', + placeholder: 'Customer first name', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + }, + { + id: 'familyName', + title: 'Last Name', + type: 'short-input', + placeholder: 'Customer last name', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + }, + { + id: 'companyName', + title: 'Company Name', + type: 'short-input', + placeholder: 'Customer business name', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + mode: 'advanced', + }, + { + id: 'emailAddress', + title: 'Email Address', + type: 'short-input', + placeholder: 'customer@example.com', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + }, + { + id: 'phoneNumber', + title: 'Phone Number', + type: 'short-input', + placeholder: '+15551234567', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + mode: 'advanced', + }, + { + id: 'address', + title: 'Address (JSON)', + type: 'code', + language: 'json', + placeholder: '{"address_line_1": "123 Main St", "locality": "New York", "country": "US"}', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + mode: 'advanced', + }, + { + id: 'sortField', + title: 'Sort Field', + type: 'dropdown', + options: [ + { label: 'Default', id: 'DEFAULT' }, + { label: 'Created At', id: 'CREATED_AT' }, + ], + condition: { field: 'operation', value: 'list_customers' }, + mode: 'advanced', + }, + { + id: 'sortOrder', + title: 'Sort Order', + type: 'dropdown', + options: [ + { label: 'Ascending', id: 'ASC' }, + { label: 'Descending', id: 'DESC' }, + ], + condition: { field: 'operation', value: 'list_customers' }, + mode: 'advanced', + }, + + // Shared note / reference (payments + customers) + { + id: 'note', + title: 'Note', + type: 'long-input', + placeholder: 'Optional note', + condition: { + field: 'operation', + value: ['create_payment', 'create_customer', 'update_customer'], + }, + mode: 'advanced', + }, + { + id: 'referenceId', + title: 'Reference ID', + type: 'short-input', + placeholder: 'Optional external reference', + condition: { + field: 'operation', + value: ['create_payment', 'create_customer', 'update_customer'], + }, + mode: 'advanced', + }, + + // Search query (customers / orders / catalog) + { + id: 'query', + title: 'Query (JSON)', + type: 'code', + language: 'json', + placeholder: '{"filter": {"email_address": {"exact": "customer@example.com"}}}', + condition: { + field: 'operation', + value: ['search_customers', 'search_orders', 'search_catalog_objects'], + }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate a Square search query JSON object for the given operation. Return ONLY the JSON object.', + generationType: 'json-object', + }, + }, + + // Orders + { + id: 'order', + title: 'Order (JSON)', + type: 'code', + language: 'json', + placeholder: + '{"location_id": "L123", "line_items": [{"name": "Coffee", "quantity": "1", "base_price_money": {"amount": 250, "currency": "USD"}}]}', + condition: { field: 'operation', value: 'create_order' }, + required: { field: 'operation', value: 'create_order' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a Square order JSON object with a location_id and line_items. Return ONLY the JSON object.', + generationType: 'json-object', + }, + }, + { + id: 'orderId', + title: 'Order ID', + type: 'short-input', + placeholder: 'Square order ID', + condition: { field: 'operation', value: ['create_payment', 'get_order', 'pay_order'] }, + required: { field: 'operation', value: ['get_order', 'pay_order'] }, + }, + { + id: 'paymentIds', + title: 'Payment IDs (JSON Array)', + type: 'code', + language: 'json', + placeholder: '["paymentId1", "paymentId2"]', + condition: { field: 'operation', value: 'pay_order' }, + mode: 'advanced', + }, + { + id: 'orderVersion', + title: 'Order Version', + type: 'short-input', + placeholder: 'Current order version', + condition: { field: 'operation', value: 'pay_order' }, + mode: 'advanced', + }, + { + id: 'locationIds', + title: 'Location IDs (JSON Array)', + type: 'code', + language: 'json', + placeholder: '["L123", "L456"]', + condition: { + field: 'operation', + value: ['search_orders', 'search_invoices', 'batch_retrieve_inventory_counts'], + }, + required: { field: 'operation', value: ['search_orders', 'search_invoices'] }, + }, + + // Invoices + { + id: 'invoice', + title: 'Invoice (JSON)', + type: 'code', + language: 'json', + placeholder: + '{"location_id": "L123", "order_id": "O123", "primary_recipient": {"customer_id": "C123"}, "payment_requests": [{"request_type": "BALANCE"}]}', + condition: { field: 'operation', value: 'create_invoice' }, + required: { field: 'operation', value: 'create_invoice' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a Square invoice JSON object with location_id, order_id, primary_recipient, and payment_requests. Return ONLY the JSON object.', + generationType: 'json-object', + }, + }, + { + id: 'invoiceId', + title: 'Invoice ID', + type: 'short-input', + placeholder: 'Square invoice ID', + condition: { + field: 'operation', + value: ['get_invoice', 'publish_invoice', 'cancel_invoice', 'delete_invoice'], + }, + required: { + field: 'operation', + value: ['get_invoice', 'publish_invoice', 'cancel_invoice', 'delete_invoice'], + }, + }, + { + id: 'version', + title: 'Invoice Version', + type: 'short-input', + placeholder: 'Current invoice version (e.g. 0)', + condition: { + field: 'operation', + value: ['publish_invoice', 'cancel_invoice', 'delete_invoice'], + }, + required: { field: 'operation', value: ['publish_invoice', 'cancel_invoice'] }, + }, + + // Catalog + { + id: 'object', + title: 'Catalog Object (JSON)', + type: 'code', + language: 'json', + placeholder: '{"type": "ITEM", "id": "#Coffee", "item_data": {"name": "Coffee"}}', + condition: { field: 'operation', value: 'upsert_catalog_object' }, + required: { field: 'operation', value: 'upsert_catalog_object' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a Square catalog object JSON for upsert. Use a temporary id like "#Name" for new objects. Return ONLY the JSON object.', + generationType: 'json-object', + }, + }, + { + id: 'objectId', + title: 'Catalog Object ID', + type: 'short-input', + placeholder: 'Square catalog object ID', + condition: { + field: 'operation', + value: ['get_catalog_object', 'create_catalog_image', 'delete_catalog_object'], + }, + required: { field: 'operation', value: ['get_catalog_object', 'delete_catalog_object'] }, + }, + { + id: 'catalogObjectIds', + title: 'Catalog Object IDs (JSON Array)', + type: 'code', + language: 'json', + placeholder: '["variationId1", "variationId2"]', + condition: { field: 'operation', value: 'batch_retrieve_inventory_counts' }, + mode: 'advanced', + }, + { + id: 'includeRelatedObjects', + title: 'Include Related Objects', + type: 'dropdown', + options: [ + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + condition: { field: 'operation', value: 'get_catalog_object' }, + mode: 'advanced', + }, + { + id: 'types', + title: 'Types', + type: 'short-input', + placeholder: 'Comma-separated (e.g. ITEM,CATEGORY)', + condition: { field: 'operation', value: 'list_catalog' }, + mode: 'advanced', + }, + { + id: 'objectTypes', + title: 'Object Types (JSON Array)', + type: 'code', + language: 'json', + placeholder: '["ITEM", "CATEGORY"]', + condition: { field: 'operation', value: 'search_catalog_objects' }, + mode: 'advanced', + }, + + // Catalog image upload (file) + { + id: 'uploadFile', + title: 'Image File', + type: 'file-upload', + canonicalParamId: 'file', + placeholder: 'Upload an image', + acceptedTypes: 'image/*', + mode: 'basic', + multiple: false, + condition: { field: 'operation', value: 'create_catalog_image' }, + required: { field: 'operation', value: 'create_catalog_image' }, + }, + { + id: 'fileRef', + title: 'Image File', + type: 'short-input', + canonicalParamId: 'file', + placeholder: 'Reference an image from previous blocks', + mode: 'advanced', + condition: { field: 'operation', value: 'create_catalog_image' }, + required: { field: 'operation', value: 'create_catalog_image' }, + }, + { + id: 'fileName', + title: 'File Name', + type: 'short-input', + placeholder: 'Optional filename override', + condition: { field: 'operation', value: 'create_catalog_image' }, + mode: 'advanced', + }, + { + id: 'caption', + title: 'Caption', + type: 'short-input', + placeholder: 'Image caption (alt text)', + condition: { field: 'operation', value: 'create_catalog_image' }, + }, + + // Shared pagination (list / search) + { + id: 'locationId', + title: 'Location ID', + type: 'short-input', + placeholder: 'Square location ID', + condition: { + field: 'operation', + value: ['create_payment', 'list_payments', 'list_invoices', 'list_refunds', 'get_location'], + }, + required: { field: 'operation', value: ['list_invoices', 'get_location'] }, + }, + { + id: 'limit', + title: 'Limit', + type: 'short-input', + placeholder: 'Max results per page', + condition: { + field: 'operation', + value: [ + 'list_payments', + 'list_refunds', + 'list_customers', + 'search_customers', + 'search_orders', + 'list_invoices', + 'search_invoices', + 'search_catalog_objects', + ], + }, + mode: 'advanced', + }, + { + id: 'cursor', + title: 'Cursor', + type: 'short-input', + placeholder: 'Pagination cursor from a previous response', + condition: { + field: 'operation', + value: [ + 'list_payments', + 'list_refunds', + 'list_customers', + 'search_customers', + 'search_orders', + 'list_invoices', + 'search_invoices', + 'search_catalog_objects', + 'list_catalog', + 'batch_retrieve_inventory_counts', + ], + }, + mode: 'advanced', + }, + + // Idempotency (create-style operations) + { + id: 'idempotencyKey', + title: 'Idempotency Key', + type: 'short-input', + placeholder: 'Optional unique key (auto-generated if omitted)', + condition: { + field: 'operation', + value: [ + 'create_payment', + 'refund_payment', + 'create_customer', + 'create_order', + 'pay_order', + 'create_invoice', + 'publish_invoice', + 'upsert_catalog_object', + 'create_catalog_image', + ], + }, + mode: 'advanced', + }, + ], + + tools: { + access: [ + 'square_create_payment', + 'square_get_payment', + 'square_list_payments', + 'square_cancel_payment', + 'square_complete_payment', + 'square_refund_payment', + 'square_get_refund', + 'square_list_refunds', + 'square_create_customer', + 'square_get_customer', + 'square_list_customers', + 'square_search_customers', + 'square_update_customer', + 'square_delete_customer', + 'square_list_locations', + 'square_get_location', + 'square_create_order', + 'square_get_order', + 'square_search_orders', + 'square_pay_order', + 'square_create_invoice', + 'square_get_invoice', + 'square_list_invoices', + 'square_search_invoices', + 'square_publish_invoice', + 'square_cancel_invoice', + 'square_delete_invoice', + 'square_upsert_catalog_object', + 'square_get_catalog_object', + 'square_list_catalog', + 'square_search_catalog_objects', + 'square_create_catalog_image', + 'square_delete_catalog_object', + 'square_batch_retrieve_inventory_counts', + ], + config: { + tool: (params) => `square_${params.operation}`, + params: (params) => { + const { + operation, + uploadFile, + fileRef, + address, + query, + order, + invoice, + object, + locationIds, + objectTypes, + paymentIds, + catalogObjectIds, + amount, + limit, + version, + orderVersion, + autocomplete, + includeRelatedObjects, + ...rest + } = params + + // Normalize the catalog image file from basic (uploadFile) or advanced (fileRef) + const normalizedFile = normalizeFileInput(uploadFile || fileRef, { single: true }) + + // Parse JSON-typed inputs + let parsedAddress: unknown + let parsedQuery: unknown + let parsedOrder: unknown + let parsedInvoice: unknown + let parsedObject: unknown + let parsedLocationIds: unknown + let parsedObjectTypes: unknown + let parsedPaymentIds: unknown + let parsedCatalogObjectIds: unknown + try { + if (address) parsedAddress = JSON.parse(address) + if (query) parsedQuery = JSON.parse(query) + if (order) parsedOrder = JSON.parse(order) + if (invoice) parsedInvoice = JSON.parse(invoice) + if (object) parsedObject = JSON.parse(object) + if (locationIds) parsedLocationIds = JSON.parse(locationIds) + if (objectTypes) parsedObjectTypes = JSON.parse(objectTypes) + if (paymentIds) parsedPaymentIds = JSON.parse(paymentIds) + if (catalogObjectIds) parsedCatalogObjectIds = JSON.parse(catalogObjectIds) + } catch (error) { + throw new Error( + `Invalid JSON input: ${error instanceof Error ? error.message : 'unknown error'}` + ) + } + + return { + ...rest, + ...(normalizedFile && { file: normalizedFile }), + ...(parsedAddress !== undefined && { address: parsedAddress }), + ...(parsedQuery !== undefined && { query: parsedQuery }), + ...(parsedOrder !== undefined && { order: parsedOrder }), + ...(parsedInvoice !== undefined && { invoice: parsedInvoice }), + ...(parsedObject !== undefined && { object: parsedObject }), + ...(parsedLocationIds !== undefined && { locationIds: parsedLocationIds }), + ...(parsedObjectTypes !== undefined && { objectTypes: parsedObjectTypes }), + ...(parsedPaymentIds !== undefined && { paymentIds: parsedPaymentIds }), + ...(parsedCatalogObjectIds !== undefined && { catalogObjectIds: parsedCatalogObjectIds }), + ...(amount !== undefined && amount !== '' && { amount: Number(amount) }), + ...(limit !== undefined && limit !== '' && { limit: Number(limit) }), + ...(version !== undefined && version !== '' && { version: Number(version) }), + ...(orderVersion !== undefined && + orderVersion !== '' && { orderVersion: Number(orderVersion) }), + ...(autocomplete !== undefined && { autocomplete: autocomplete === 'true' }), + ...(includeRelatedObjects !== undefined && { + includeRelatedObjects: includeRelatedObjects === 'true', + }), + } + }, + }, + }, + + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'Square access token' }, + sourceId: { type: 'string', description: 'Payment source ID' }, + paymentId: { type: 'string', description: 'Payment ID' }, + refundId: { type: 'string', description: 'Refund ID' }, + status: { type: 'string', description: 'Status filter' }, + amount: { type: 'number', description: 'Amount in smallest currency denomination' }, + currency: { type: 'string', description: 'ISO 4217 currency code' }, + reason: { type: 'string', description: 'Refund reason' }, + autocomplete: { type: 'boolean', description: 'Capture payment immediately' }, + beginTime: { type: 'string', description: 'Start of the reporting period (RFC 3339)' }, + endTime: { type: 'string', description: 'End of the reporting period (RFC 3339)' }, + customerId: { type: 'string', description: 'Customer ID' }, + givenName: { type: 'string', description: 'Customer first name' }, + familyName: { type: 'string', description: 'Customer last name' }, + companyName: { type: 'string', description: 'Customer company name' }, + emailAddress: { type: 'string', description: 'Customer email address' }, + phoneNumber: { type: 'string', description: 'Customer phone number' }, + address: { type: 'json', description: 'Customer address object' }, + note: { type: 'string', description: 'Note' }, + referenceId: { type: 'string', description: 'External reference ID' }, + sortField: { type: 'string', description: 'Field to sort by' }, + sortOrder: { type: 'string', description: 'Sort order (ASC or DESC)' }, + query: { type: 'json', description: 'Search query object' }, + order: { type: 'json', description: 'Order object' }, + orderId: { type: 'string', description: 'Order ID' }, + orderVersion: { type: 'number', description: 'Order version for payment' }, + paymentIds: { type: 'json', description: 'Array of payment IDs to apply to an order' }, + locationIds: { type: 'json', description: 'Array of location IDs' }, + invoice: { type: 'json', description: 'Invoice object' }, + invoiceId: { type: 'string', description: 'Invoice ID' }, + version: { type: 'number', description: 'Invoice version' }, + object: { type: 'json', description: 'Catalog object' }, + objectId: { type: 'string', description: 'Catalog object ID' }, + includeRelatedObjects: { type: 'boolean', description: 'Include related catalog objects' }, + types: { type: 'string', description: 'Comma-separated catalog object types' }, + objectTypes: { type: 'json', description: 'Array of catalog object types to search' }, + catalogObjectIds: { type: 'json', description: 'Array of catalog object IDs for inventory' }, + file: { type: 'json', description: 'Image file to upload (canonical param)' }, + fileName: { type: 'string', description: 'Filename override for the image' }, + caption: { type: 'string', description: 'Image caption' }, + locationId: { type: 'string', description: 'Location ID' }, + limit: { type: 'number', description: 'Maximum results to return' }, + cursor: { type: 'string', description: 'Pagination cursor' }, + idempotencyKey: { type: 'string', description: 'Idempotency key' }, + }, + + outputs: { + payment: { type: 'json', description: 'Payment object' }, + payments: { type: 'json', description: 'Array of payment objects' }, + refund: { type: 'json', description: 'Refund object' }, + refunds: { type: 'json', description: 'Array of refund objects' }, + customer: { type: 'json', description: 'Customer object' }, + customers: { type: 'json', description: 'Array of customer objects' }, + location: { type: 'json', description: 'Location object' }, + locations: { type: 'json', description: 'Array of location objects' }, + order: { type: 'json', description: 'Order object' }, + orders: { type: 'json', description: 'Array of order objects' }, + invoice: { type: 'json', description: 'Invoice object' }, + invoices: { type: 'json', description: 'Array of invoice objects' }, + object: { type: 'json', description: 'Catalog object' }, + objects: { type: 'json', description: 'Array of catalog objects' }, + counts: { type: 'json', description: 'Array of inventory count objects' }, + deleted: { type: 'boolean', description: 'Whether the resource was deleted' }, + deleted_object_ids: { type: 'json', description: 'IDs of deleted catalog objects' }, + deleted_at: { type: 'string', description: 'Timestamp when deletion occurred' }, + id: { type: 'string', description: 'ID of the affected resource' }, + metadata: { type: 'json', description: 'Operation summary metadata' }, + }, +} + +export const SquareBlockMeta = { + tags: ['payments', 'subscriptions', 'automation'], + url: 'https://squareup.com', + templates: [ + { + icon: SquareIcon, + title: 'Daily sales summary', + prompt: + 'Build a scheduled daily workflow that lists Square payments from the previous day across all locations, totals gross sales, refunds, and net revenue, writes the figures to a table for historical tracking, and posts a Slack summary with day-over-day trends.', + modules: ['scheduled', 'tables', 'agent', 'workflows'], + category: 'operations', + tags: ['finance', 'reporting', 'founder'], + alsoIntegrations: ['slack'], + }, + { + icon: SquareIcon, + title: 'Refund pattern monitor', + prompt: + 'Create a scheduled weekly workflow that lists Square payments and their refunds, classifies each refund by reason and location, flags any location with an unusually high refund rate, and emails finance a narrative report with recommended actions.', + modules: ['scheduled', 'agent', 'files', 'workflows'], + category: 'operations', + tags: ['finance', 'analysis', 'monitoring'], + alsoIntegrations: ['gmail'], + }, + { + icon: SquareIcon, + title: 'New customer welcome', + prompt: + 'Build a workflow that takes a new Square customer, creates a welcome email tailored to their purchase, adds them to an onboarding tracking table, and posts a notification to the customer success Slack channel.', + modules: ['tables', 'agent', 'workflows'], + category: 'operations', + tags: ['sales', 'automation'], + alsoIntegrations: ['gmail', 'slack'], + }, + { + icon: SquareIcon, + title: 'Invoice chase automation', + prompt: + 'Create a scheduled workflow that lists Square invoices for a location, finds those that are unpaid past their due date, sends a polite reminder email per customer, and logs every chase action to a collections table.', + modules: ['scheduled', 'tables', 'agent', 'workflows'], + category: 'operations', + tags: ['finance', 'automation', 'reporting'], + alsoIntegrations: ['gmail'], + }, + { + icon: SquareIcon, + title: 'Catalog image enrichment', + prompt: + 'Build a workflow that lists Square catalog items missing images, generates a product image for each one, uploads it as a catalog image attached to the item, and writes a report of which items were updated.', + modules: ['agent', 'files', 'workflows'], + category: 'operations', + tags: ['ecommerce', 'automation'], + }, + { + icon: SquareIcon, + title: 'Low-stock reorder alerts', + prompt: + 'Create a scheduled workflow that lists the Square catalog, identifies items flagged as low or out of stock, drafts a reorder summary grouped by supplier, and posts it to a Slack purchasing channel with the items and quantities to reorder.', + modules: ['scheduled', 'agent', 'workflows'], + category: 'operations', + tags: ['ecommerce', 'operations'], + alsoIntegrations: ['slack'], + }, + { + icon: SquareIcon, + title: 'Customer purchase history lookup', + prompt: + 'Build a workflow that searches Square customers by email, pulls their orders and payments, summarizes lifetime spend and most-purchased items, and returns a concise profile the support team can use during a conversation.', + modules: ['agent', 'workflows'], + category: 'support', + tags: ['support', 'analysis'], + }, + ], + skills: [ + { + name: 'take-payment', + description: 'Take a Square payment from a payment source and confirm the result.', + content: + '# Take Payment\n\nCharge a customer using Square.\n\n## Steps\n1. Run Create Payment with the source ID (card nonce or card on file), the amount in the smallest denomination, and the currency.\n2. Optionally attach a customer ID, location ID, or order ID.\n3. Confirm the result with Get Payment if you need the latest status.\n\n## Output\nReturn the payment ID, status (APPROVED, COMPLETED, or FAILED), and the amount charged. If a refund is needed, run Refund Payment with the payment ID.', + }, + { + name: 'issue-and-publish-invoice', + description: 'Create a Square invoice for an order and publish it to the customer.', + content: + '# Issue And Publish Invoice\n\nBill a customer with a Square invoice.\n\n## Steps\n1. Make sure an order exists (use Create Order if needed) and you have the customer ID.\n2. Run Create Invoice with an invoice object referencing the location, order, primary recipient (customer), and payment requests. Note the returned invoice ID and version.\n3. Run Publish Invoice with that invoice ID and version to send it to the customer.\n4. Track payment with Get Invoice.\n\n## Output\nReturn the invoice ID, status, and the public URL where the customer can pay.', + }, + { + name: 'manage-catalog-item', + description: 'Create or update a Square catalog item and attach an image to it.', + content: + '# Manage Catalog Item\n\nBuild out the Square catalog.\n\n## Steps\n1. Run Upsert Catalog Object with an ITEM object (use a temporary id like "#Name" for new items). Capture the returned object ID.\n2. To add a picture, run Create Catalog Image with the image file and the object ID to attach it to the item.\n3. Verify with Get Catalog Object or Search Catalog Objects.\n\n## Output\nReturn the catalog object ID, type, and version, plus the image object ID when an image was attached.', + }, + { + name: 'find-customer-activity', + description: 'Look up a Square customer and summarize their orders and payments.', + content: + '# Find Customer Activity\n\nBuild a purchase history view for one customer.\n\n## Steps\n1. Run Search Customers (by email or phone) or Get Customer to identify the customer and their ID.\n2. Run Search Orders across the relevant locations filtered to that customer.\n3. Run List Payments and match payments to the customer for a full financial picture.\n\n## Output\nReturn the customer ID and email plus a summary of their orders and payments: total spend, number of orders, and any refunds.', + }, + ], +} as const satisfies BlockMeta diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index 88f03250471..1d2066d2656 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -268,6 +268,7 @@ import { SlackBlock, SlackBlockMeta } from '@/blocks/blocks/slack' import { SmtpBlock } from '@/blocks/blocks/smtp' import { SpotifyBlock, SpotifyBlockMeta } from '@/blocks/blocks/spotify' import { SQSBlock, SQSBlockMeta } from '@/blocks/blocks/sqs' +import { SquareBlock, SquareBlockMeta } from '@/blocks/blocks/square' import { SSHBlock } from '@/blocks/blocks/ssh' import { StagehandBlock, StagehandBlockMeta } from '@/blocks/blocks/stagehand' import { StartTriggerBlock } from '@/blocks/blocks/start_trigger' @@ -569,6 +570,7 @@ const BLOCK_REGISTRY: Record = { smtp: SmtpBlock, spotify: SpotifyBlock, sqs: SQSBlock, + square: SquareBlock, ssh: SSHBlock, stagehand: StagehandBlock, start_trigger: StartTriggerBlock, @@ -827,6 +829,7 @@ const BLOCK_META_REGISTRY: Record = { slack: SlackBlockMeta, spotify: SpotifyBlockMeta, sqs: SQSBlockMeta, + square: SquareBlockMeta, stagehand: StagehandBlockMeta, stripe: StripeBlockMeta, sts: STSBlockMeta, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index dc3c91c5bef..2d6b6eb2c03 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -1958,6 +1958,17 @@ export function WhatsAppIcon(props: SVGProps) { ) } +export function SquareIcon(props: SVGProps) { + return ( + + + + ) +} + export function StripeIcon(props: SVGProps) { return ( + +export const squareCatalogImageContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/square/catalog-image', + body: squareCatalogImageBodySchema, + response: { mode: 'json', schema: squareCatalogImageResponseSchema }, +}) diff --git a/apps/sim/lib/integrations/icon-mapping.ts b/apps/sim/lib/integrations/icon-mapping.ts index 9dc7ae5b4cf..04b349d7c43 100644 --- a/apps/sim/lib/integrations/icon-mapping.ts +++ b/apps/sim/lib/integrations/icon-mapping.ts @@ -190,6 +190,7 @@ import { SlackIcon, SmtpIcon, SQSIcon, + SquareIcon, SshIcon, STSIcon, STTIcon, @@ -415,6 +416,7 @@ export const blockTypeToIconMap: Record = { slack: SlackIcon, smtp: SmtpIcon, sqs: SQSIcon, + square: SquareIcon, ssh: SshIcon, stagehand: StagehandIcon, stripe: StripeIcon, diff --git a/apps/sim/lib/integrations/integrations.json b/apps/sim/lib/integrations/integrations.json index 219fed3b77c..64e1d3ebc1c 100644 --- a/apps/sim/lib/integrations/integrations.json +++ b/apps/sim/lib/integrations/integrations.json @@ -14660,6 +14660,161 @@ "category": "tools", "integrationType": "email" }, + { + "type": "square", + "slug": "square", + "name": "Square", + "description": "Process payments and manage Square commerce data", + "longDescription": "Integrate Square into the workflow. Take and refund payments, manage customers, build catalog items and images, create and search orders, and issue invoices. Authenticate with a Square access token (personal access token).", + "bgColor": "#000000", + "iconName": "SquareIcon", + "docsUrl": "https://docs.sim.ai/integrations/square", + "operations": [ + { + "name": "Create Payment", + "description": "Take a payment using a payment source such as a card nonce or a card on file" + }, + { + "name": "Get Payment", + "description": "Retrieve details for a single payment by its ID" + }, + { + "name": "List Payments", + "description": "List payments taken by the account, optionally filtered by location and time range" + }, + { + "name": "Cancel Payment", + "description": "Cancel (void) an authorized payment that has not been captured" + }, + { + "name": "Complete Payment", + "description": "Capture (complete) a payment that was authorized with delayed capture" + }, + { + "name": "Refund Payment", + "description": "Refund all or part of a completed payment" + }, + { + "name": "Get Refund", + "description": "Retrieve a single payment refund by its ID" + }, + { + "name": "List Refunds", + "description": "List payment refunds, optionally filtered by location, status, and time range" + }, + { + "name": "Create Customer", + "description": "Create a new customer profile in the Square customer directory" + }, + { + "name": "Get Customer", + "description": "Retrieve a single customer profile by its ID" + }, + { + "name": "List Customers", + "description": "List customer profiles in the Square customer directory" + }, + { + "name": "Search Customers", + "description": "Search customer profiles using filters such as email, phone, or creation date" + }, + { + "name": "Update Customer", + "description": "Update fields on an existing customer profile" + }, + { + "name": "Delete Customer", + "description": "Delete a customer profile from the Square customer directory" + }, + { + "name": "List Locations", + "description": "List all locations associated with the Square account" + }, + { + "name": "Get Location", + "description": "Retrieve a single location by its ID" + }, + { + "name": "Create Order", + "description": "Create an order with line items, taxes, discounts, and fulfillments" + }, + { + "name": "Get Order", + "description": "Retrieve a single order by its ID" + }, + { + "name": "Search Orders", + "description": "Search orders across one or more locations using filters and sorting" + }, + { + "name": "Pay Order", + "description": "Pay for an order using one or more already-approved payments" + }, + { + "name": "Create Invoice", + "description": "Create a draft invoice for an existing order and customer" + }, + { + "name": "Get Invoice", + "description": "Retrieve a single invoice by its ID" + }, + { + "name": "List Invoices", + "description": "List invoices for a specific location" + }, + { + "name": "Search Invoices", + "description": "Search invoices across one or more locations" + }, + { + "name": "Publish Invoice", + "description": "Publish a draft invoice so it is sent to the customer and becomes payable" + }, + { + "name": "Cancel Invoice", + "description": "Cancel a published invoice that is unpaid or partially paid" + }, + { + "name": "Delete Invoice", + "description": "Delete a draft invoice" + }, + { + "name": "Upsert Catalog Object", + "description": "Create or update a catalog object such as an item, variation, or category" + }, + { + "name": "Get Catalog Object", + "description": "Retrieve a single catalog object by its ID" + }, + { + "name": "List Catalog", + "description": "List catalog objects, optionally filtered by type" + }, + { + "name": "Search Catalog Objects", + "description": "Search catalog objects by type and query filters" + }, + { + "name": "Create Catalog Image", + "description": "Upload an image and attach it to the catalog, optionally to a specific item" + }, + { + "name": "Delete Catalog Object", + "description": "Delete a catalog object and its children (e.g. an item and its variations)" + }, + { + "name": "Batch Retrieve Inventory Counts", + "description": "Retrieve current inventory counts for catalog items across locations" + } + ], + "operationCount": 34, + "triggers": [], + "triggerCount": 0, + "authType": "api-key", + "category": "tools", + "integrationType": "commerce", + "tags": ["payments", "subscriptions", "automation"] + }, { "type": "ssh", "slug": "ssh", diff --git a/apps/sim/tools/error-extractors.ts b/apps/sim/tools/error-extractors.ts index ff4c442e64b..0bfc70c7c57 100644 --- a/apps/sim/tools/error-extractors.ts +++ b/apps/sim/tools/error-extractors.ts @@ -176,6 +176,17 @@ const ERROR_EXTRACTORS: ErrorExtractorConfig[] = [ examples: ['Hunter.io API'], extract: (errorInfo) => errorInfo?.data?.errors?.[0]?.details, }, + { + id: 'square-errors', + description: 'Square API error format with errors[].detail and errors[].code', + examples: ['Square API'], + extract: (errorInfo) => { + const err = errorInfo?.data?.errors?.[0] + if (!err) return undefined + if (err.detail) return err.code ? `${err.detail} (${err.code})` : err.detail + return err.code + }, + }, { id: 'errors-array-string', description: 'Errors array containing strings or objects with messages', @@ -302,6 +313,7 @@ export const ErrorExtractorId = { BATCH_VALIDATION_ERRORS: 'batch-validation-errors', NESTJS_VALIDATION_ERRORS: 'nestjs-validation-errors', HUNTER_ERRORS: 'hunter-errors', + SQUARE_ERRORS: 'square-errors', ERRORS_ARRAY_STRING: 'errors-array-string', TELEGRAM_DESCRIPTION: 'telegram-description', STANDARD_MESSAGE: 'standard-message', diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index a5ffd6ba05d..45fef1980aa 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -3135,6 +3135,42 @@ import { spotifyUpdatePlaylistTool, } from '@/tools/spotify' import { sqsSendTool } from '@/tools/sqs' +import { + squareBatchRetrieveInventoryCountsTool, + squareCancelInvoiceTool, + squareCancelPaymentTool, + squareCompletePaymentTool, + squareCreateCatalogImageTool, + squareCreateCustomerTool, + squareCreateInvoiceTool, + squareCreateOrderTool, + squareCreatePaymentTool, + squareDeleteCatalogObjectTool, + squareDeleteCustomerTool, + squareDeleteInvoiceTool, + squareGetCatalogObjectTool, + squareGetCustomerTool, + squareGetInvoiceTool, + squareGetLocationTool, + squareGetOrderTool, + squareGetPaymentTool, + squareGetRefundTool, + squareListCatalogTool, + squareListCustomersTool, + squareListInvoicesTool, + squareListLocationsTool, + squareListPaymentsTool, + squareListRefundsTool, + squarePayOrderTool, + squarePublishInvoiceTool, + squareRefundPaymentTool, + squareSearchCatalogObjectsTool, + squareSearchCustomersTool, + squareSearchInvoicesTool, + squareSearchOrdersTool, + squareUpdateCustomerTool, + squareUpsertCatalogObjectTool, +} from '@/tools/square' import { sshCheckCommandExistsTool, sshCheckFileExistsTool, @@ -7045,6 +7081,40 @@ export const tools: Record = { spotify_set_repeat: spotifySetRepeatTool, spotify_set_shuffle: spotifySetShuffleTool, spotify_transfer_playback: spotifyTransferPlaybackTool, + square_create_payment: squareCreatePaymentTool, + square_get_payment: squareGetPaymentTool, + square_list_payments: squareListPaymentsTool, + square_cancel_payment: squareCancelPaymentTool, + square_complete_payment: squareCompletePaymentTool, + square_refund_payment: squareRefundPaymentTool, + square_get_refund: squareGetRefundTool, + square_list_refunds: squareListRefundsTool, + square_create_customer: squareCreateCustomerTool, + square_get_customer: squareGetCustomerTool, + square_list_customers: squareListCustomersTool, + square_search_customers: squareSearchCustomersTool, + square_update_customer: squareUpdateCustomerTool, + square_delete_customer: squareDeleteCustomerTool, + square_list_locations: squareListLocationsTool, + square_get_location: squareGetLocationTool, + square_create_order: squareCreateOrderTool, + square_get_order: squareGetOrderTool, + square_search_orders: squareSearchOrdersTool, + square_pay_order: squarePayOrderTool, + square_create_invoice: squareCreateInvoiceTool, + square_get_invoice: squareGetInvoiceTool, + square_list_invoices: squareListInvoicesTool, + square_search_invoices: squareSearchInvoicesTool, + square_publish_invoice: squarePublishInvoiceTool, + square_cancel_invoice: squareCancelInvoiceTool, + square_delete_invoice: squareDeleteInvoiceTool, + square_upsert_catalog_object: squareUpsertCatalogObjectTool, + square_get_catalog_object: squareGetCatalogObjectTool, + square_list_catalog: squareListCatalogTool, + square_search_catalog_objects: squareSearchCatalogObjectsTool, + square_create_catalog_image: squareCreateCatalogImageTool, + square_delete_catalog_object: squareDeleteCatalogObjectTool, + square_batch_retrieve_inventory_counts: squareBatchRetrieveInventoryCountsTool, upstash_redis_get: upstashRedisGetTool, upstash_redis_set: upstashRedisSetTool, upstash_redis_delete: upstashRedisDeleteTool, diff --git a/apps/sim/tools/square/batch_retrieve_inventory_counts.ts b/apps/sim/tools/square/batch_retrieve_inventory_counts.ts new file mode 100644 index 00000000000..d9779d8f127 --- /dev/null +++ b/apps/sim/tools/square/batch_retrieve_inventory_counts.ts @@ -0,0 +1,91 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { + BatchRetrieveInventoryCountsParams, + InventoryCountListResponse, +} from '@/tools/square/types' +import { + INVENTORY_COUNT_OUTPUT, + LIST_METADATA_OUTPUT_PROPERTIES, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareBatchRetrieveInventoryCountsTool: ToolConfig< + BatchRetrieveInventoryCountsParams, + InventoryCountListResponse +> = { + id: 'square_batch_retrieve_inventory_counts', + name: 'Square Batch Retrieve Inventory Counts', + description: 'Retrieve current inventory counts for catalog items across locations', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + catalogObjectIds: { + type: 'array', + required: false, + visibility: 'user-or-llm', + description: 'IDs of the catalog item variations to retrieve counts for', + }, + locationIds: { + type: 'array', + required: false, + visibility: 'user-or-llm', + description: 'IDs of the locations to retrieve counts for (defaults to all locations)', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/inventory/counts/batch-retrieve`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = {} + if (params.catalogObjectIds) body.catalog_object_ids = params.catalogObjectIds + if (params.locationIds) body.location_ids = params.locationIds + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const counts = data.counts ?? [] + return { + success: true, + output: { + counts, + metadata: { + count: counts.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + counts: { + type: 'array', + description: 'Array of inventory count objects', + items: INVENTORY_COUNT_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/cancel_invoice.ts b/apps/sim/tools/square/cancel_invoice.ts new file mode 100644 index 00000000000..8e864146db4 --- /dev/null +++ b/apps/sim/tools/square/cancel_invoice.ts @@ -0,0 +1,71 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CancelInvoiceParams, InvoiceResponse } from '@/tools/square/types' +import { + INVOICE_METADATA_OUTPUT_PROPERTIES, + INVOICE_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCancelInvoiceTool: ToolConfig = { + id: 'square_cancel_invoice', + name: 'Square Cancel Invoice', + description: 'Cancel a published invoice that is unpaid or partially paid', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + invoiceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the invoice to cancel', + }, + version: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Current version of the invoice', + }, + }, + + request: { + url: (params) => + `${SQUARE_BASE_URL}/v2/invoices/${encodeURIComponent(params.invoiceId)}/cancel`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => ({ version: params.version }), + }, + + transformResponse: async (response) => { + const data = await response.json() + const invoice = data.invoice ?? {} + return { + success: true, + output: { + invoice, + metadata: { + id: invoice.id, + status: invoice.status ?? null, + version: invoice.version ?? null, + }, + }, + } + }, + + outputs: { + invoice: { ...INVOICE_OUTPUT, description: 'The canceled invoice object' }, + metadata: { + type: 'json', + description: 'Invoice summary metadata', + properties: INVOICE_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/cancel_payment.ts b/apps/sim/tools/square/cancel_payment.ts new file mode 100644 index 00000000000..8e4b4a7b81f --- /dev/null +++ b/apps/sim/tools/square/cancel_payment.ts @@ -0,0 +1,65 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CancelPaymentParams, PaymentResponse } from '@/tools/square/types' +import { + PAYMENT_METADATA_OUTPUT_PROPERTIES, + PAYMENT_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCancelPaymentTool: ToolConfig = { + id: 'square_cancel_payment', + name: 'Square Cancel Payment', + description: 'Cancel (void) an authorized payment that has not been captured', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + paymentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the payment to cancel', + }, + }, + + request: { + url: (params) => + `${SQUARE_BASE_URL}/v2/payments/${encodeURIComponent(params.paymentId)}/cancel`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: () => ({}), + }, + + transformResponse: async (response) => { + const data = await response.json() + const payment = data.payment ?? {} + return { + success: true, + output: { + payment, + metadata: { + id: payment.id, + status: payment.status ?? null, + order_id: payment.order_id ?? null, + }, + }, + } + }, + + outputs: { + payment: { ...PAYMENT_OUTPUT, description: 'The canceled payment object' }, + metadata: { + type: 'json', + description: 'Payment summary metadata', + properties: PAYMENT_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/complete_payment.ts b/apps/sim/tools/square/complete_payment.ts new file mode 100644 index 00000000000..7216a40b9c6 --- /dev/null +++ b/apps/sim/tools/square/complete_payment.ts @@ -0,0 +1,65 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CompletePaymentParams, PaymentResponse } from '@/tools/square/types' +import { + PAYMENT_METADATA_OUTPUT_PROPERTIES, + PAYMENT_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCompletePaymentTool: ToolConfig = { + id: 'square_complete_payment', + name: 'Square Complete Payment', + description: 'Capture (complete) a payment that was authorized with delayed capture', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + paymentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the payment to complete', + }, + }, + + request: { + url: (params) => + `${SQUARE_BASE_URL}/v2/payments/${encodeURIComponent(params.paymentId)}/complete`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: () => ({}), + }, + + transformResponse: async (response) => { + const data = await response.json() + const payment = data.payment ?? {} + return { + success: true, + output: { + payment, + metadata: { + id: payment.id, + status: payment.status ?? null, + order_id: payment.order_id ?? null, + }, + }, + } + }, + + outputs: { + payment: { ...PAYMENT_OUTPUT, description: 'The completed payment object' }, + metadata: { + type: 'json', + description: 'Payment summary metadata', + properties: PAYMENT_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/create_catalog_image.ts b/apps/sim/tools/square/create_catalog_image.ts new file mode 100644 index 00000000000..8c8fc8dc135 --- /dev/null +++ b/apps/sim/tools/square/create_catalog_image.ts @@ -0,0 +1,98 @@ +import type { CatalogObjectResponse, CreateCatalogImageParams } from '@/tools/square/types' +import { + CATALOG_OBJECT_METADATA_OUTPUT_PROPERTIES, + CATALOG_OBJECT_OUTPUT, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCreateCatalogImageTool: ToolConfig< + CreateCatalogImageParams, + CatalogObjectResponse +> = { + id: 'square_create_catalog_image', + name: 'Square Create Catalog Image', + description: 'Upload an image and attach it to the catalog, optionally to a specific item', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + file: { + type: 'file', + required: false, + visibility: 'user-or-llm', + description: 'The image file to upload (UserFile object)', + }, + fileContent: { + type: 'string', + required: false, + visibility: 'hidden', + description: 'Legacy: base64 encoded image content', + }, + fileName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional filename override for the image', + }, + objectId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'ID of the catalog object (e.g. an item) to attach the image to', + }, + caption: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Caption (alt text) for the image', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + }, + + request: { + url: '/api/tools/square/catalog-image', + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params) => ({ + accessToken: params.apiKey, + file: params.file, + fileContent: params.fileContent, + fileName: params.fileName, + objectId: params.objectId, + caption: params.caption, + idempotencyKey: params.idempotencyKey, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + if (!data.success) { + throw new Error(data.error || 'Failed to upload catalog image') + } + return { + success: true, + output: data.output, + } + }, + + outputs: { + object: { ...CATALOG_OBJECT_OUTPUT, description: 'The created catalog image object' }, + metadata: { + type: 'json', + description: 'Catalog object summary metadata', + properties: CATALOG_OBJECT_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/create_customer.ts b/apps/sim/tools/square/create_customer.ts new file mode 100644 index 00000000000..a6ab2a51275 --- /dev/null +++ b/apps/sim/tools/square/create_customer.ts @@ -0,0 +1,127 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CreateCustomerParams, CustomerResponse } from '@/tools/square/types' +import { + CUSTOMER_METADATA_OUTPUT_PROPERTIES, + CUSTOMER_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCreateCustomerTool: ToolConfig = { + id: 'square_create_customer', + name: 'Square Create Customer', + description: 'Create a new customer profile in the Square customer directory', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + givenName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'First name of the customer', + }, + familyName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Last name of the customer', + }, + companyName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Business name of the customer', + }, + emailAddress: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Email address of the customer', + }, + phoneNumber: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Phone number of the customer', + }, + note: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Note about the customer', + }, + referenceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional external reference for the customer', + }, + address: { + type: 'json', + required: false, + visibility: 'user-or-llm', + description: 'Square address object for the customer', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/customers`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + idempotency_key: params.idempotencyKey || generateId(), + } + if (params.givenName) body.given_name = params.givenName + if (params.familyName) body.family_name = params.familyName + if (params.companyName) body.company_name = params.companyName + if (params.emailAddress) body.email_address = params.emailAddress + if (params.phoneNumber) body.phone_number = params.phoneNumber + if (params.note) body.note = params.note + if (params.referenceId) body.reference_id = params.referenceId + if (params.address) body.address = params.address + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const customer = data.customer ?? {} + return { + success: true, + output: { + customer, + metadata: { + id: customer.id, + email_address: customer.email_address ?? null, + given_name: customer.given_name ?? null, + family_name: customer.family_name ?? null, + }, + }, + } + }, + + outputs: { + customer: { ...CUSTOMER_OUTPUT, description: 'The created customer object' }, + metadata: { + type: 'json', + description: 'Customer summary metadata', + properties: CUSTOMER_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/create_invoice.ts b/apps/sim/tools/square/create_invoice.ts new file mode 100644 index 00000000000..bd5e82a8dd8 --- /dev/null +++ b/apps/sim/tools/square/create_invoice.ts @@ -0,0 +1,75 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CreateInvoiceParams, InvoiceResponse } from '@/tools/square/types' +import { + INVOICE_METADATA_OUTPUT_PROPERTIES, + INVOICE_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCreateInvoiceTool: ToolConfig = { + id: 'square_create_invoice', + name: 'Square Create Invoice', + description: 'Create a draft invoice for an existing order and customer', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + invoice: { + type: 'json', + required: true, + visibility: 'user-or-llm', + description: + 'Square invoice object including location_id, order_id, primary_recipient, and payment_requests (e.g. {"location_id":"L1","order_id":"O1","primary_recipient":{"customer_id":"C1"},"payment_requests":[{"request_type":"BALANCE","due_date":"2026-07-01"}]})', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/invoices`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => ({ + idempotency_key: params.idempotencyKey || generateId(), + invoice: params.invoice, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + const invoice = data.invoice ?? {} + return { + success: true, + output: { + invoice, + metadata: { + id: invoice.id, + status: invoice.status ?? null, + version: invoice.version ?? null, + }, + }, + } + }, + + outputs: { + invoice: { ...INVOICE_OUTPUT, description: 'The created invoice object' }, + metadata: { + type: 'json', + description: 'Invoice summary metadata', + properties: INVOICE_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/create_order.ts b/apps/sim/tools/square/create_order.ts new file mode 100644 index 00000000000..5cd023b3ab9 --- /dev/null +++ b/apps/sim/tools/square/create_order.ts @@ -0,0 +1,75 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CreateOrderParams, OrderResponse } from '@/tools/square/types' +import { + ORDER_METADATA_OUTPUT_PROPERTIES, + ORDER_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCreateOrderTool: ToolConfig = { + id: 'square_create_order', + name: 'Square Create Order', + description: 'Create an order with line items, taxes, discounts, and fulfillments', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + order: { + type: 'json', + required: true, + visibility: 'user-or-llm', + description: + 'Square order object including location_id and line_items (e.g. {"location_id":"L1","line_items":[{"name":"Coffee","quantity":"1","base_price_money":{"amount":250,"currency":"USD"}}]})', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/orders`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => ({ + idempotency_key: params.idempotencyKey || generateId(), + order: params.order, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + const order = data.order ?? {} + return { + success: true, + output: { + order, + metadata: { + id: order.id, + state: order.state ?? null, + location_id: order.location_id ?? null, + }, + }, + } + }, + + outputs: { + order: { ...ORDER_OUTPUT, description: 'The created order object' }, + metadata: { + type: 'json', + description: 'Order summary metadata', + properties: ORDER_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/create_payment.ts b/apps/sim/tools/square/create_payment.ts new file mode 100644 index 00000000000..02380bf8605 --- /dev/null +++ b/apps/sim/tools/square/create_payment.ts @@ -0,0 +1,132 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CreatePaymentParams, PaymentResponse } from '@/tools/square/types' +import { + PAYMENT_METADATA_OUTPUT_PROPERTIES, + PAYMENT_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareCreatePaymentTool: ToolConfig = { + id: 'square_create_payment', + name: 'Square Create Payment', + description: 'Take a payment using a payment source such as a card nonce or a card on file', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + sourceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the payment source (card nonce, card-on-file ID, or wallet token)', + }, + amount: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Amount in the smallest currency denomination (e.g. 1000 = $10.00)', + }, + currency: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Three-letter ISO 4217 currency code (e.g. USD)', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + customerId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'ID of the customer associated with the payment', + }, + locationId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'ID of the location where the payment is taken (defaults to the main location)', + }, + orderId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'ID of the order associated with the payment', + }, + referenceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional external reference for the payment', + }, + note: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional note attached to the payment', + }, + autocomplete: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to immediately capture the payment (defaults to true)', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/payments`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + idempotency_key: params.idempotencyKey || generateId(), + source_id: params.sourceId, + amount_money: { amount: params.amount, currency: params.currency }, + } + if (params.customerId) body.customer_id = params.customerId + if (params.locationId) body.location_id = params.locationId + if (params.orderId) body.order_id = params.orderId + if (params.referenceId) body.reference_id = params.referenceId + if (params.note) body.note = params.note + if (params.autocomplete !== undefined) body.autocomplete = params.autocomplete + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const payment = data.payment ?? {} + return { + success: true, + output: { + payment, + metadata: { + id: payment.id, + status: payment.status ?? null, + order_id: payment.order_id ?? null, + }, + }, + } + }, + + outputs: { + payment: { ...PAYMENT_OUTPUT, description: 'The created payment object' }, + metadata: { + type: 'json', + description: 'Payment summary metadata', + properties: PAYMENT_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/delete_catalog_object.ts b/apps/sim/tools/square/delete_catalog_object.ts new file mode 100644 index 00000000000..9cf1e37a095 --- /dev/null +++ b/apps/sim/tools/square/delete_catalog_object.ts @@ -0,0 +1,62 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CatalogDeleteResponse, DeleteCatalogObjectParams } from '@/tools/square/types' +import { SQUARE_BASE_URL, squareHeaders } from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareDeleteCatalogObjectTool: ToolConfig< + DeleteCatalogObjectParams, + CatalogDeleteResponse +> = { + id: 'square_delete_catalog_object', + name: 'Square Delete Catalog Object', + description: 'Delete a catalog object and its children (e.g. an item and its variations)', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + objectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the catalog object to delete', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/catalog/object/${encodeURIComponent(params.objectId)}`, + method: 'DELETE', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + return { + success: true, + output: { + deleted: true, + deleted_object_ids: data.deleted_object_ids ?? [], + deleted_at: data.deleted_at ?? null, + }, + } + }, + + outputs: { + deleted: { type: 'boolean', description: 'Whether the catalog object was deleted' }, + deleted_object_ids: { + type: 'array', + description: 'IDs of all catalog objects deleted (including children)', + items: { type: 'string' }, + }, + deleted_at: { + type: 'string', + description: 'Timestamp when the deletion occurred (RFC 3339)', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/square/delete_customer.ts b/apps/sim/tools/square/delete_customer.ts new file mode 100644 index 00000000000..14d255d31ce --- /dev/null +++ b/apps/sim/tools/square/delete_customer.ts @@ -0,0 +1,49 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CustomerDeleteResponse, DeleteCustomerParams } from '@/tools/square/types' +import { SQUARE_BASE_URL, squareHeaders } from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareDeleteCustomerTool: ToolConfig = { + id: 'square_delete_customer', + name: 'Square Delete Customer', + description: 'Delete a customer profile from the Square customer directory', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + customerId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the customer to delete', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/customers/${encodeURIComponent(params.customerId)}`, + method: 'DELETE', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response, params) => { + await response.json().catch(() => ({})) + return { + success: true, + output: { + deleted: true, + id: params?.customerId ?? '', + }, + } + }, + + outputs: { + deleted: { type: 'boolean', description: 'Whether the customer was deleted' }, + id: { type: 'string', description: 'ID of the deleted customer' }, + }, +} diff --git a/apps/sim/tools/square/delete_invoice.ts b/apps/sim/tools/square/delete_invoice.ts new file mode 100644 index 00000000000..4b8e8064825 --- /dev/null +++ b/apps/sim/tools/square/delete_invoice.ts @@ -0,0 +1,60 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { DeleteInvoiceParams, InvoiceDeleteResponse } from '@/tools/square/types' +import { SQUARE_BASE_URL, squareHeaders } from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareDeleteInvoiceTool: ToolConfig = { + id: 'square_delete_invoice', + name: 'Square Delete Invoice', + description: 'Delete a draft invoice', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + invoiceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the draft invoice to delete', + }, + version: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Current version of the invoice (required if the invoice has been updated)', + }, + }, + + request: { + url: (params) => { + const url = new URL(`${SQUARE_BASE_URL}/v2/invoices/${encodeURIComponent(params.invoiceId)}`) + if (params.version !== undefined) + url.searchParams.append('version', params.version.toString()) + return url.toString() + }, + method: 'DELETE', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response, params) => { + await response.json().catch(() => ({})) + return { + success: true, + output: { + deleted: true, + id: params?.invoiceId ?? '', + }, + } + }, + + outputs: { + deleted: { type: 'boolean', description: 'Whether the invoice was deleted' }, + id: { type: 'string', description: 'ID of the deleted invoice' }, + }, +} diff --git a/apps/sim/tools/square/get_catalog_object.ts b/apps/sim/tools/square/get_catalog_object.ts new file mode 100644 index 00000000000..d6651041f39 --- /dev/null +++ b/apps/sim/tools/square/get_catalog_object.ts @@ -0,0 +1,78 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CatalogObjectResponse, GetCatalogObjectParams } from '@/tools/square/types' +import { + CATALOG_OBJECT_METADATA_OUTPUT_PROPERTIES, + CATALOG_OBJECT_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareGetCatalogObjectTool: ToolConfig = + { + id: 'square_get_catalog_object', + name: 'Square Get Catalog Object', + description: 'Retrieve a single catalog object by its ID', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + objectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the catalog object to retrieve', + }, + includeRelatedObjects: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to include related objects such as an item variations', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `${SQUARE_BASE_URL}/v2/catalog/object/${encodeURIComponent(params.objectId)}` + ) + if (params.includeRelatedObjects !== undefined) { + url.searchParams.append('include_related_objects', String(params.includeRelatedObjects)) + } + return url.toString() + }, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const object = data.object ?? {} + return { + success: true, + output: { + object, + metadata: { + id: object.id, + type: object.type ?? null, + version: object.version ?? null, + }, + }, + } + }, + + outputs: { + object: { ...CATALOG_OBJECT_OUTPUT, description: 'The retrieved catalog object' }, + metadata: { + type: 'json', + description: 'Catalog object summary metadata', + properties: CATALOG_OBJECT_METADATA_OUTPUT_PROPERTIES, + }, + }, + } diff --git a/apps/sim/tools/square/get_customer.ts b/apps/sim/tools/square/get_customer.ts new file mode 100644 index 00000000000..950aca1457e --- /dev/null +++ b/apps/sim/tools/square/get_customer.ts @@ -0,0 +1,64 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CustomerResponse, GetCustomerParams } from '@/tools/square/types' +import { + CUSTOMER_METADATA_OUTPUT_PROPERTIES, + CUSTOMER_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareGetCustomerTool: ToolConfig = { + id: 'square_get_customer', + name: 'Square Get Customer', + description: 'Retrieve a single customer profile by its ID', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + customerId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the customer to retrieve', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/customers/${encodeURIComponent(params.customerId)}`, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const customer = data.customer ?? {} + return { + success: true, + output: { + customer, + metadata: { + id: customer.id, + email_address: customer.email_address ?? null, + given_name: customer.given_name ?? null, + family_name: customer.family_name ?? null, + }, + }, + } + }, + + outputs: { + customer: { ...CUSTOMER_OUTPUT, description: 'The retrieved customer object' }, + metadata: { + type: 'json', + description: 'Customer summary metadata', + properties: CUSTOMER_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/get_invoice.ts b/apps/sim/tools/square/get_invoice.ts new file mode 100644 index 00000000000..bc89c9b6c61 --- /dev/null +++ b/apps/sim/tools/square/get_invoice.ts @@ -0,0 +1,63 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { GetInvoiceParams, InvoiceResponse } from '@/tools/square/types' +import { + INVOICE_METADATA_OUTPUT_PROPERTIES, + INVOICE_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareGetInvoiceTool: ToolConfig = { + id: 'square_get_invoice', + name: 'Square Get Invoice', + description: 'Retrieve a single invoice by its ID', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + invoiceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the invoice to retrieve', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/invoices/${encodeURIComponent(params.invoiceId)}`, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const invoice = data.invoice ?? {} + return { + success: true, + output: { + invoice, + metadata: { + id: invoice.id, + status: invoice.status ?? null, + version: invoice.version ?? null, + }, + }, + } + }, + + outputs: { + invoice: { ...INVOICE_OUTPUT, description: 'The retrieved invoice object' }, + metadata: { + type: 'json', + description: 'Invoice summary metadata', + properties: INVOICE_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/get_location.ts b/apps/sim/tools/square/get_location.ts new file mode 100644 index 00000000000..17ae2755e8e --- /dev/null +++ b/apps/sim/tools/square/get_location.ts @@ -0,0 +1,60 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { GetLocationParams, LocationResponse } from '@/tools/square/types' +import { LOCATION_OUTPUT, SQUARE_BASE_URL, squareHeaders } from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareGetLocationTool: ToolConfig = { + id: 'square_get_location', + name: 'Square Get Location', + description: 'Retrieve a single location by its ID', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + locationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the location to retrieve (use "main" for the main location)', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/locations/${encodeURIComponent(params.locationId)}`, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const location = data.location ?? {} + return { + success: true, + output: { + location, + metadata: { + id: location.id, + name: location.name ?? null, + }, + }, + } + }, + + outputs: { + location: { ...LOCATION_OUTPUT, description: 'The retrieved location object' }, + metadata: { + type: 'json', + description: 'Location summary metadata', + properties: { + id: { type: 'string', description: 'Square location ID' }, + name: { type: 'string', description: 'Location name', optional: true }, + }, + }, + }, +} diff --git a/apps/sim/tools/square/get_order.ts b/apps/sim/tools/square/get_order.ts new file mode 100644 index 00000000000..b2277a32d6e --- /dev/null +++ b/apps/sim/tools/square/get_order.ts @@ -0,0 +1,63 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { GetOrderParams, OrderResponse } from '@/tools/square/types' +import { + ORDER_METADATA_OUTPUT_PROPERTIES, + ORDER_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareGetOrderTool: ToolConfig = { + id: 'square_get_order', + name: 'Square Get Order', + description: 'Retrieve a single order by its ID', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + orderId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the order to retrieve', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/orders/${encodeURIComponent(params.orderId)}`, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const order = data.order ?? {} + return { + success: true, + output: { + order, + metadata: { + id: order.id, + state: order.state ?? null, + location_id: order.location_id ?? null, + }, + }, + } + }, + + outputs: { + order: { ...ORDER_OUTPUT, description: 'The retrieved order object' }, + metadata: { + type: 'json', + description: 'Order summary metadata', + properties: ORDER_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/get_payment.ts b/apps/sim/tools/square/get_payment.ts new file mode 100644 index 00000000000..9114aa80a7e --- /dev/null +++ b/apps/sim/tools/square/get_payment.ts @@ -0,0 +1,63 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { GetPaymentParams, PaymentResponse } from '@/tools/square/types' +import { + PAYMENT_METADATA_OUTPUT_PROPERTIES, + PAYMENT_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareGetPaymentTool: ToolConfig = { + id: 'square_get_payment', + name: 'Square Get Payment', + description: 'Retrieve details for a single payment by its ID', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + paymentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the payment to retrieve', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/payments/${encodeURIComponent(params.paymentId)}`, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const payment = data.payment ?? {} + return { + success: true, + output: { + payment, + metadata: { + id: payment.id, + status: payment.status ?? null, + order_id: payment.order_id ?? null, + }, + }, + } + }, + + outputs: { + payment: { ...PAYMENT_OUTPUT, description: 'The retrieved payment object' }, + metadata: { + type: 'json', + description: 'Payment summary metadata', + properties: PAYMENT_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/get_refund.ts b/apps/sim/tools/square/get_refund.ts new file mode 100644 index 00000000000..3ca9bc78030 --- /dev/null +++ b/apps/sim/tools/square/get_refund.ts @@ -0,0 +1,63 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { GetRefundParams, RefundResponse } from '@/tools/square/types' +import { + REFUND_METADATA_OUTPUT_PROPERTIES, + REFUND_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareGetRefundTool: ToolConfig = { + id: 'square_get_refund', + name: 'Square Get Refund', + description: 'Retrieve a single payment refund by its ID', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + refundId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the refund to retrieve', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/refunds/${encodeURIComponent(params.refundId)}`, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const refund = data.refund ?? {} + return { + success: true, + output: { + refund, + metadata: { + id: refund.id, + status: refund.status ?? null, + payment_id: refund.payment_id ?? null, + }, + }, + } + }, + + outputs: { + refund: { ...REFUND_OUTPUT, description: 'The retrieved refund object' }, + metadata: { + type: 'json', + description: 'Refund summary metadata', + properties: REFUND_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/index.ts b/apps/sim/tools/square/index.ts new file mode 100644 index 00000000000..9daac26ec51 --- /dev/null +++ b/apps/sim/tools/square/index.ts @@ -0,0 +1,34 @@ +export { squareBatchRetrieveInventoryCountsTool } from '@/tools/square/batch_retrieve_inventory_counts' +export { squareCancelInvoiceTool } from '@/tools/square/cancel_invoice' +export { squareCancelPaymentTool } from '@/tools/square/cancel_payment' +export { squareCompletePaymentTool } from '@/tools/square/complete_payment' +export { squareCreateCatalogImageTool } from '@/tools/square/create_catalog_image' +export { squareCreateCustomerTool } from '@/tools/square/create_customer' +export { squareCreateInvoiceTool } from '@/tools/square/create_invoice' +export { squareCreateOrderTool } from '@/tools/square/create_order' +export { squareCreatePaymentTool } from '@/tools/square/create_payment' +export { squareDeleteCatalogObjectTool } from '@/tools/square/delete_catalog_object' +export { squareDeleteCustomerTool } from '@/tools/square/delete_customer' +export { squareDeleteInvoiceTool } from '@/tools/square/delete_invoice' +export { squareGetCatalogObjectTool } from '@/tools/square/get_catalog_object' +export { squareGetCustomerTool } from '@/tools/square/get_customer' +export { squareGetInvoiceTool } from '@/tools/square/get_invoice' +export { squareGetLocationTool } from '@/tools/square/get_location' +export { squareGetOrderTool } from '@/tools/square/get_order' +export { squareGetPaymentTool } from '@/tools/square/get_payment' +export { squareGetRefundTool } from '@/tools/square/get_refund' +export { squareListCatalogTool } from '@/tools/square/list_catalog' +export { squareListCustomersTool } from '@/tools/square/list_customers' +export { squareListInvoicesTool } from '@/tools/square/list_invoices' +export { squareListLocationsTool } from '@/tools/square/list_locations' +export { squareListPaymentsTool } from '@/tools/square/list_payments' +export { squareListRefundsTool } from '@/tools/square/list_refunds' +export { squarePayOrderTool } from '@/tools/square/pay_order' +export { squarePublishInvoiceTool } from '@/tools/square/publish_invoice' +export { squareRefundPaymentTool } from '@/tools/square/refund_payment' +export { squareSearchCatalogObjectsTool } from '@/tools/square/search_catalog_objects' +export { squareSearchCustomersTool } from '@/tools/square/search_customers' +export { squareSearchInvoicesTool } from '@/tools/square/search_invoices' +export { squareSearchOrdersTool } from '@/tools/square/search_orders' +export { squareUpdateCustomerTool } from '@/tools/square/update_customer' +export { squareUpsertCatalogObjectTool } from '@/tools/square/upsert_catalog_object' diff --git a/apps/sim/tools/square/list_catalog.ts b/apps/sim/tools/square/list_catalog.ts new file mode 100644 index 00000000000..04ad484a93c --- /dev/null +++ b/apps/sim/tools/square/list_catalog.ts @@ -0,0 +1,78 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CatalogListResponse, ListCatalogParams } from '@/tools/square/types' +import { + CATALOG_OBJECT_OUTPUT, + LIST_METADATA_OUTPUT_PROPERTIES, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareListCatalogTool: ToolConfig = { + id: 'square_list_catalog', + name: 'Square List Catalog', + description: 'List catalog objects, optionally filtered by type', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + types: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Comma-separated catalog object types to return (e.g. ITEM,CATEGORY). Defaults to all top-level types', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: (params) => { + const url = new URL(`${SQUARE_BASE_URL}/v2/catalog/list`) + if (params.types) url.searchParams.append('types', params.types) + if (params.cursor) url.searchParams.append('cursor', params.cursor) + return url.toString() + }, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const objects = data.objects ?? [] + return { + success: true, + output: { + objects, + metadata: { + count: objects.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + objects: { + type: 'array', + description: 'Array of catalog objects', + items: CATALOG_OBJECT_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/list_customers.ts b/apps/sim/tools/square/list_customers.ts new file mode 100644 index 00000000000..7ffe04cec41 --- /dev/null +++ b/apps/sim/tools/square/list_customers.ts @@ -0,0 +1,91 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CustomerListResponse, ListCustomersParams } from '@/tools/square/types' +import { + CUSTOMER_OUTPUT, + LIST_METADATA_OUTPUT_PROPERTIES, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareListCustomersTool: ToolConfig = { + id: 'square_list_customers', + name: 'Square List Customers', + description: 'List customer profiles in the Square customer directory', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page (max 100)', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + sortField: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Field to sort by (DEFAULT or CREATED_AT)', + }, + sortOrder: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Sort order (ASC or DESC)', + }, + }, + + request: { + url: (params) => { + const url = new URL(`${SQUARE_BASE_URL}/v2/customers`) + if (params.limit !== undefined) url.searchParams.append('limit', params.limit.toString()) + if (params.cursor) url.searchParams.append('cursor', params.cursor) + if (params.sortField) url.searchParams.append('sort_field', params.sortField) + if (params.sortOrder) url.searchParams.append('sort_order', params.sortOrder) + return url.toString() + }, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const customers = data.customers ?? [] + return { + success: true, + output: { + customers, + metadata: { + count: customers.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + customers: { + type: 'array', + description: 'Array of customer objects', + items: CUSTOMER_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/list_invoices.ts b/apps/sim/tools/square/list_invoices.ts new file mode 100644 index 00000000000..752dc018d11 --- /dev/null +++ b/apps/sim/tools/square/list_invoices.ts @@ -0,0 +1,84 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { InvoiceListResponse, ListInvoicesParams } from '@/tools/square/types' +import { + INVOICE_OUTPUT, + LIST_METADATA_OUTPUT_PROPERTIES, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareListInvoicesTool: ToolConfig = { + id: 'square_list_invoices', + name: 'Square List Invoices', + description: 'List invoices for a specific location', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + locationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the location to list invoices for', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: (params) => { + const url = new URL(`${SQUARE_BASE_URL}/v2/invoices`) + url.searchParams.append('location_id', params.locationId) + if (params.limit !== undefined) url.searchParams.append('limit', params.limit.toString()) + if (params.cursor) url.searchParams.append('cursor', params.cursor) + return url.toString() + }, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const invoices = data.invoices ?? [] + return { + success: true, + output: { + invoices, + metadata: { + count: invoices.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + invoices: { + type: 'array', + description: 'Array of invoice objects', + items: INVOICE_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/list_locations.ts b/apps/sim/tools/square/list_locations.ts new file mode 100644 index 00000000000..e52bbaf6acd --- /dev/null +++ b/apps/sim/tools/square/list_locations.ts @@ -0,0 +1,56 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { ListLocationsParams, LocationListResponse } from '@/tools/square/types' +import { LOCATION_OUTPUT, SQUARE_BASE_URL, squareHeaders } from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareListLocationsTool: ToolConfig = { + id: 'square_list_locations', + name: 'Square List Locations', + description: 'List all locations associated with the Square account', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/locations`, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const locations = data.locations ?? [] + return { + success: true, + output: { + locations, + metadata: { + count: locations.length, + }, + }, + } + }, + + outputs: { + locations: { + type: 'array', + description: 'Array of location objects', + items: LOCATION_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List metadata', + properties: { + count: { type: 'number', description: 'Number of locations returned' }, + }, + }, + }, +} diff --git a/apps/sim/tools/square/list_payments.ts b/apps/sim/tools/square/list_payments.ts new file mode 100644 index 00000000000..8ae3495390b --- /dev/null +++ b/apps/sim/tools/square/list_payments.ts @@ -0,0 +1,98 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { ListPaymentsParams, PaymentListResponse } from '@/tools/square/types' +import { + LIST_METADATA_OUTPUT_PROPERTIES, + PAYMENT_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareListPaymentsTool: ToolConfig = { + id: 'square_list_payments', + name: 'Square List Payments', + description: 'List payments taken by the account, optionally filtered by location and time range', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + locationId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter payments by location ID', + }, + beginTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'RFC 3339 timestamp for the beginning of the reporting period', + }, + endTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'RFC 3339 timestamp for the end of the reporting period', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: (params) => { + const url = new URL(`${SQUARE_BASE_URL}/v2/payments`) + if (params.locationId) url.searchParams.append('location_id', params.locationId) + if (params.beginTime) url.searchParams.append('begin_time', params.beginTime) + if (params.endTime) url.searchParams.append('end_time', params.endTime) + if (params.limit !== undefined) url.searchParams.append('limit', params.limit.toString()) + if (params.cursor) url.searchParams.append('cursor', params.cursor) + return url.toString() + }, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const payments = data.payments ?? [] + return { + success: true, + output: { + payments, + metadata: { + count: payments.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + payments: { + type: 'array', + description: 'Array of payment objects', + items: PAYMENT_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/list_refunds.ts b/apps/sim/tools/square/list_refunds.ts new file mode 100644 index 00000000000..c63cac762e6 --- /dev/null +++ b/apps/sim/tools/square/list_refunds.ts @@ -0,0 +1,105 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { ListRefundsParams, RefundListResponse } from '@/tools/square/types' +import { + LIST_METADATA_OUTPUT_PROPERTIES, + REFUND_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareListRefundsTool: ToolConfig = { + id: 'square_list_refunds', + name: 'Square List Refunds', + description: 'List payment refunds, optionally filtered by location, status, and time range', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + locationId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter refunds by location ID', + }, + status: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by refund status (PENDING, COMPLETED, REJECTED, or FAILED)', + }, + beginTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'RFC 3339 timestamp for the beginning of the reporting period', + }, + endTime: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'RFC 3339 timestamp for the end of the reporting period', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: (params) => { + const url = new URL(`${SQUARE_BASE_URL}/v2/refunds`) + if (params.locationId) url.searchParams.append('location_id', params.locationId) + if (params.status) url.searchParams.append('status', params.status) + if (params.beginTime) url.searchParams.append('begin_time', params.beginTime) + if (params.endTime) url.searchParams.append('end_time', params.endTime) + if (params.limit !== undefined) url.searchParams.append('limit', params.limit.toString()) + if (params.cursor) url.searchParams.append('cursor', params.cursor) + return url.toString() + }, + method: 'GET', + headers: (params) => squareHeaders(params.apiKey), + }, + + transformResponse: async (response) => { + const data = await response.json() + const refunds = data.refunds ?? [] + return { + success: true, + output: { + refunds, + metadata: { + count: refunds.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + refunds: { + type: 'array', + description: 'Array of refund objects', + items: REFUND_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/pay_order.ts b/apps/sim/tools/square/pay_order.ts new file mode 100644 index 00000000000..d2b60122ff2 --- /dev/null +++ b/apps/sim/tools/square/pay_order.ts @@ -0,0 +1,90 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { OrderResponse, PayOrderParams } from '@/tools/square/types' +import { + ORDER_METADATA_OUTPUT_PROPERTIES, + ORDER_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squarePayOrderTool: ToolConfig = { + id: 'square_pay_order', + name: 'Square Pay Order', + description: 'Pay for an order using one or more already-approved payments', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + orderId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the order to pay for', + }, + paymentIds: { + type: 'array', + required: false, + visibility: 'user-or-llm', + description: 'IDs of approved payments to apply to the order', + }, + orderVersion: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Version of the order being paid (for optimistic concurrency)', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/orders/${encodeURIComponent(params.orderId)}/pay`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + idempotency_key: params.idempotencyKey || generateId(), + } + if (params.paymentIds) body.payment_ids = params.paymentIds + if (params.orderVersion !== undefined) body.order_version = params.orderVersion + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const order = data.order ?? {} + return { + success: true, + output: { + order, + metadata: { + id: order.id, + state: order.state ?? null, + location_id: order.location_id ?? null, + }, + }, + } + }, + + outputs: { + order: { ...ORDER_OUTPUT, description: 'The paid order object' }, + metadata: { + type: 'json', + description: 'Order summary metadata', + properties: ORDER_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/publish_invoice.ts b/apps/sim/tools/square/publish_invoice.ts new file mode 100644 index 00000000000..418d1468c78 --- /dev/null +++ b/apps/sim/tools/square/publish_invoice.ts @@ -0,0 +1,81 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { InvoiceResponse, PublishInvoiceParams } from '@/tools/square/types' +import { + INVOICE_METADATA_OUTPUT_PROPERTIES, + INVOICE_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squarePublishInvoiceTool: ToolConfig = { + id: 'square_publish_invoice', + name: 'Square Publish Invoice', + description: 'Publish a draft invoice so it is sent to the customer and becomes payable', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + invoiceId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the invoice to publish', + }, + version: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Current version of the invoice (use the version returned by Create Invoice)', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + }, + + request: { + url: (params) => + `${SQUARE_BASE_URL}/v2/invoices/${encodeURIComponent(params.invoiceId)}/publish`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => ({ + version: params.version, + idempotency_key: params.idempotencyKey || generateId(), + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + const invoice = data.invoice ?? {} + return { + success: true, + output: { + invoice, + metadata: { + id: invoice.id, + status: invoice.status ?? null, + version: invoice.version ?? null, + }, + }, + } + }, + + outputs: { + invoice: { ...INVOICE_OUTPUT, description: 'The published invoice object' }, + metadata: { + type: 'json', + description: 'Invoice summary metadata', + properties: INVOICE_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/refund_payment.ts b/apps/sim/tools/square/refund_payment.ts new file mode 100644 index 00000000000..91cad5ce6a4 --- /dev/null +++ b/apps/sim/tools/square/refund_payment.ts @@ -0,0 +1,97 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { RefundPaymentParams, RefundResponse } from '@/tools/square/types' +import { + REFUND_METADATA_OUTPUT_PROPERTIES, + REFUND_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareRefundPaymentTool: ToolConfig = { + id: 'square_refund_payment', + name: 'Square Refund Payment', + description: 'Refund all or part of a completed payment', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + paymentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the payment to refund', + }, + amount: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Amount to refund in the smallest currency denomination (e.g. 100 = $1.00)', + }, + currency: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Three-letter ISO 4217 currency code (e.g. USD)', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + reason: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Reason for the refund', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/refunds`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + idempotency_key: params.idempotencyKey || generateId(), + payment_id: params.paymentId, + amount_money: { amount: params.amount, currency: params.currency }, + } + if (params.reason) body.reason = params.reason + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const refund = data.refund ?? {} + return { + success: true, + output: { + refund, + metadata: { + id: refund.id, + status: refund.status ?? null, + payment_id: refund.payment_id ?? null, + }, + }, + } + }, + + outputs: { + refund: { ...REFUND_OUTPUT, description: 'The created refund object' }, + metadata: { + type: 'json', + description: 'Refund summary metadata', + properties: REFUND_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/search_catalog_objects.ts b/apps/sim/tools/square/search_catalog_objects.ts new file mode 100644 index 00000000000..c0cbb73678d --- /dev/null +++ b/apps/sim/tools/square/search_catalog_objects.ts @@ -0,0 +1,96 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CatalogListResponse, SearchCatalogObjectsParams } from '@/tools/square/types' +import { + CATALOG_OBJECT_OUTPUT, + LIST_METADATA_OUTPUT_PROPERTIES, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareSearchCatalogObjectsTool: ToolConfig< + SearchCatalogObjectsParams, + CatalogListResponse +> = { + id: 'square_search_catalog_objects', + name: 'Square Search Catalog Objects', + description: 'Search catalog objects by type and query filters', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + objectTypes: { + type: 'array', + required: false, + visibility: 'user-or-llm', + description: 'Array of catalog object types to search (e.g. ["ITEM","CATEGORY"])', + }, + query: { + type: 'json', + required: false, + visibility: 'user-or-llm', + description: + 'Square catalog query object (e.g. {"text_query":{"keywords":["coffee"]}} or {"prefix_query":{...}})', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/catalog/search`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = {} + if (params.objectTypes) body.object_types = params.objectTypes + if (params.query) body.query = params.query + if (params.limit !== undefined) body.limit = params.limit + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const objects = data.objects ?? [] + return { + success: true, + output: { + objects, + metadata: { + count: objects.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + objects: { + type: 'array', + description: 'Array of matching catalog objects', + items: CATALOG_OBJECT_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/search_customers.ts b/apps/sim/tools/square/search_customers.ts new file mode 100644 index 00000000000..55bdf1c4980 --- /dev/null +++ b/apps/sim/tools/square/search_customers.ts @@ -0,0 +1,86 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CustomerListResponse, SearchCustomersParams } from '@/tools/square/types' +import { + CUSTOMER_OUTPUT, + LIST_METADATA_OUTPUT_PROPERTIES, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareSearchCustomersTool: ToolConfig = { + id: 'square_search_customers', + name: 'Square Search Customers', + description: 'Search customer profiles using filters such as email, phone, or creation date', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + query: { + type: 'json', + required: false, + visibility: 'user-or-llm', + description: + 'Square customer query object with optional filter and sort (e.g. {"filter":{"email_address":{"exact":"a@b.com"}}})', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/customers/search`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = {} + if (params.query) body.query = params.query + if (params.limit !== undefined) body.limit = params.limit + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const customers = data.customers ?? [] + return { + success: true, + output: { + customers, + metadata: { + count: customers.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + customers: { + type: 'array', + description: 'Array of matching customer objects', + items: CUSTOMER_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/search_invoices.ts b/apps/sim/tools/square/search_invoices.ts new file mode 100644 index 00000000000..509d1d20089 --- /dev/null +++ b/apps/sim/tools/square/search_invoices.ts @@ -0,0 +1,88 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { InvoiceListResponse, SearchInvoicesParams } from '@/tools/square/types' +import { + INVOICE_OUTPUT, + LIST_METADATA_OUTPUT_PROPERTIES, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareSearchInvoicesTool: ToolConfig = { + id: 'square_search_invoices', + name: 'Square Search Invoices', + description: 'Search invoices across one or more locations', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + locationIds: { + type: 'array', + required: true, + visibility: 'user-or-llm', + description: 'Array of location IDs to search within', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/invoices/search`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + query: { + filter: { location_ids: params.locationIds }, + }, + } + if (params.limit !== undefined) body.limit = params.limit + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const invoices = data.invoices ?? [] + return { + success: true, + output: { + invoices, + metadata: { + count: invoices.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + invoices: { + type: 'array', + description: 'Array of matching invoice objects', + items: INVOICE_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/search_orders.ts b/apps/sim/tools/square/search_orders.ts new file mode 100644 index 00000000000..07945aad0da --- /dev/null +++ b/apps/sim/tools/square/search_orders.ts @@ -0,0 +1,94 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { OrderListResponse, SearchOrdersParams } from '@/tools/square/types' +import { + LIST_METADATA_OUTPUT_PROPERTIES, + ORDER_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareSearchOrdersTool: ToolConfig = { + id: 'square_search_orders', + name: 'Square Search Orders', + description: 'Search orders across one or more locations using filters and sorting', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + locationIds: { + type: 'array', + required: true, + visibility: 'user-or-llm', + description: 'Array of location IDs to search within', + }, + query: { + type: 'json', + required: false, + visibility: 'user-or-llm', + description: + 'Square order query object with optional filter and sort (e.g. {"filter":{"state_filter":{"states":["OPEN"]}}})', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor from a previous response', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/orders/search`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + location_ids: params.locationIds, + } + if (params.query) body.query = params.query + if (params.limit !== undefined) body.limit = params.limit + if (params.cursor) body.cursor = params.cursor + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const orders = data.orders ?? [] + return { + success: true, + output: { + orders, + metadata: { + count: orders.length, + cursor: data.cursor ?? null, + }, + }, + } + }, + + outputs: { + orders: { + type: 'array', + description: 'Array of matching order objects', + items: ORDER_OUTPUT, + }, + metadata: { + type: 'json', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/types.ts b/apps/sim/tools/square/types.ts new file mode 100644 index 00000000000..b4dfad7b61c --- /dev/null +++ b/apps/sim/tools/square/types.ts @@ -0,0 +1,1070 @@ +import type { OutputProperty, ToolResponse } from '@/tools/types' + +/** + * Shared constants, output property definitions, and TypeScript interfaces for + * the Square API. Reused across all Square tools to keep request building and + * output shapes consistent. + * + * @see https://developer.squareup.com/reference/square + */ + +/** Square production API base URL. */ +export const SQUARE_BASE_URL = 'https://connect.squareup.com' + +/** + * Square API version pinned for every request via the `Square-Version` header. + * Square is a date-versioned API; pinning avoids silent breaking changes. + */ +export const SQUARE_API_VERSION = '2026-05-20' + +/** + * Standard headers for a JSON Square request authenticated with a personal + * access token (or any Square access token) as a bearer token. + */ +export function squareHeaders(apiKey: string): Record { + return { + Authorization: `Bearer ${apiKey}`, + 'Square-Version': SQUARE_API_VERSION, + 'Content-Type': 'application/json', + } +} + +/** + * Output definition for a Square Money object. + * @see https://developer.squareup.com/reference/square/objects/Money + */ +export const MONEY_OUTPUT_PROPERTIES = { + amount: { + type: 'number', + description: 'Amount in the smallest denomination of the currency (e.g. cents for USD)', + optional: true, + }, + currency: { + type: 'string', + description: 'Three-letter ISO 4217 currency code (e.g. USD)', + optional: true, + }, +} as const satisfies Record + +export const MONEY_OUTPUT: OutputProperty = { + type: 'object', + description: 'Monetary amount with a currency', + optional: true, + properties: MONEY_OUTPUT_PROPERTIES, +} + +/** + * Output definition for a Square Address object. + * @see https://developer.squareup.com/reference/square/objects/Address + */ +export const ADDRESS_OUTPUT_PROPERTIES = { + address_line_1: { type: 'string', description: 'First line of the address', optional: true }, + address_line_2: { type: 'string', description: 'Second line of the address', optional: true }, + address_line_3: { type: 'string', description: 'Third line of the address', optional: true }, + locality: { type: 'string', description: 'City or town', optional: true }, + sublocality: { type: 'string', description: 'Neighborhood or district', optional: true }, + administrative_district_level_1: { + type: 'string', + description: 'State, province, or region', + optional: true, + }, + postal_code: { type: 'string', description: 'Postal or ZIP code', optional: true }, + country: { + type: 'string', + description: 'Two-letter ISO 3166-1 alpha-2 country code', + optional: true, + }, + first_name: { type: 'string', description: 'First name of the addressee', optional: true }, + last_name: { type: 'string', description: 'Last name of the addressee', optional: true }, +} as const satisfies Record + +export const ADDRESS_OUTPUT: OutputProperty = { + type: 'object', + description: 'Physical address', + optional: true, + properties: ADDRESS_OUTPUT_PROPERTIES, +} + +/** + * Output definition for a Square Payment object. + * @see https://developer.squareup.com/reference/square/objects/Payment + */ +export const PAYMENT_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Unique ID for the payment' }, + status: { + type: 'string', + description: 'Payment status (APPROVED, PENDING, COMPLETED, CANCELED, or FAILED)', + optional: true, + }, + amount_money: MONEY_OUTPUT, + total_money: MONEY_OUTPUT, + approved_money: MONEY_OUTPUT, + app_fee_money: MONEY_OUTPUT, + refunded_money: MONEY_OUTPUT, + tip_money: MONEY_OUTPUT, + source_type: { + type: 'string', + description: 'Source of the payment (CARD, BANK_ACCOUNT, WALLET, etc.)', + optional: true, + }, + card_details: { type: 'json', description: 'Details about a card payment', optional: true }, + location_id: { + type: 'string', + description: 'ID of the location where the payment was taken', + optional: true, + }, + order_id: { type: 'string', description: 'ID of the associated order', optional: true }, + customer_id: { type: 'string', description: 'ID of the associated customer', optional: true }, + reference_id: { + type: 'string', + description: 'Optional external reference for the payment', + optional: true, + }, + receipt_number: { type: 'string', description: 'Receipt number for the payment', optional: true }, + receipt_url: { type: 'string', description: 'URL of the payment receipt', optional: true }, + note: { type: 'string', description: 'Optional note attached to the payment', optional: true }, + refund_ids: { + type: 'array', + description: 'IDs of refunds associated with the payment', + optional: true, + items: { type: 'string' }, + }, + processing_fee: { + type: 'array', + description: 'Processing fees applied to the payment', + optional: true, + items: { type: 'object' }, + }, + created_at: { type: 'string', description: 'Timestamp when the payment was created (RFC 3339)' }, + updated_at: { + type: 'string', + description: 'Timestamp when the payment was last updated (RFC 3339)', + optional: true, + }, + version_token: { + type: 'string', + description: 'Optimistic concurrency token for the payment', + optional: true, + }, +} as const satisfies Record + +export const PAYMENT_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square Payment object', + properties: PAYMENT_OUTPUT_PROPERTIES, +} + +export const PAYMENT_METADATA_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Square payment ID' }, + status: { type: 'string', description: 'Current payment status', optional: true }, + order_id: { type: 'string', description: 'Associated order ID', optional: true }, +} as const satisfies Record + +/** + * Output definition for a Square PaymentRefund object. + * @see https://developer.squareup.com/reference/square/objects/PaymentRefund + */ +export const REFUND_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Unique ID for the refund' }, + status: { + type: 'string', + description: 'Refund status (PENDING, COMPLETED, REJECTED, or FAILED)', + optional: true, + }, + amount_money: MONEY_OUTPUT, + processing_fee: { + type: 'array', + description: 'Processing fees refunded', + optional: true, + items: { type: 'object' }, + }, + payment_id: { type: 'string', description: 'ID of the payment being refunded', optional: true }, + order_id: { type: 'string', description: 'ID of the associated order', optional: true }, + location_id: { type: 'string', description: 'ID of the associated location', optional: true }, + reason: { type: 'string', description: 'Reason for the refund', optional: true }, + created_at: { type: 'string', description: 'Timestamp when the refund was created (RFC 3339)' }, + updated_at: { + type: 'string', + description: 'Timestamp when the refund was last updated (RFC 3339)', + optional: true, + }, +} as const satisfies Record + +export const REFUND_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square PaymentRefund object', + properties: REFUND_OUTPUT_PROPERTIES, +} + +export const REFUND_METADATA_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Square refund ID' }, + status: { type: 'string', description: 'Current refund status', optional: true }, + payment_id: { type: 'string', description: 'Refunded payment ID', optional: true }, +} as const satisfies Record + +/** + * Output definition for a Square Customer object. + * @see https://developer.squareup.com/reference/square/objects/Customer + */ +export const CUSTOMER_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Unique ID for the customer' }, + given_name: { type: 'string', description: 'First name of the customer', optional: true }, + family_name: { type: 'string', description: 'Last name of the customer', optional: true }, + nickname: { type: 'string', description: 'Nickname of the customer', optional: true }, + company_name: { type: 'string', description: 'Business name of the customer', optional: true }, + email_address: { type: 'string', description: 'Email address of the customer', optional: true }, + phone_number: { type: 'string', description: 'Phone number of the customer', optional: true }, + address: ADDRESS_OUTPUT, + birthday: { + type: 'string', + description: 'Birthday in YYYY-MM-DD or MM-DD format', + optional: true, + }, + reference_id: { + type: 'string', + description: 'Optional external reference for the customer', + optional: true, + }, + note: { type: 'string', description: 'Note about the customer', optional: true }, + creation_source: { + type: 'string', + description: 'How the customer profile was created', + optional: true, + }, + preferences: { type: 'json', description: 'Customer communication preferences', optional: true }, + group_ids: { + type: 'array', + description: 'IDs of customer groups the customer belongs to', + optional: true, + items: { type: 'string' }, + }, + segment_ids: { + type: 'array', + description: 'IDs of customer segments the customer belongs to', + optional: true, + items: { type: 'string' }, + }, + version: { + type: 'number', + description: 'Optimistic concurrency version of the customer', + optional: true, + }, + created_at: { type: 'string', description: 'Timestamp when the customer was created (RFC 3339)' }, + updated_at: { + type: 'string', + description: 'Timestamp when the customer was last updated (RFC 3339)', + optional: true, + }, +} as const satisfies Record + +export const CUSTOMER_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square Customer object', + properties: CUSTOMER_OUTPUT_PROPERTIES, +} + +export const CUSTOMER_METADATA_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Square customer ID' }, + email_address: { type: 'string', description: 'Customer email address', optional: true }, + given_name: { type: 'string', description: 'Customer first name', optional: true }, + family_name: { type: 'string', description: 'Customer last name', optional: true }, +} as const satisfies Record + +/** + * Output definition for a Square Location object. + * @see https://developer.squareup.com/reference/square/objects/Location + */ +export const LOCATION_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Unique ID for the location' }, + name: { type: 'string', description: 'Name of the location', optional: true }, + address: ADDRESS_OUTPUT, + timezone: { type: 'string', description: 'IANA timezone of the location', optional: true }, + status: { type: 'string', description: 'Location status (ACTIVE or INACTIVE)', optional: true }, + type: { type: 'string', description: 'Location type (PHYSICAL or MOBILE)', optional: true }, + merchant_id: { + type: 'string', + description: 'ID of the merchant that owns the location', + optional: true, + }, + country: { type: 'string', description: 'Country code of the location', optional: true }, + language_code: { type: 'string', description: 'Language code of the location', optional: true }, + currency: { type: 'string', description: 'Currency used by the location', optional: true }, + phone_number: { type: 'string', description: 'Phone number of the location', optional: true }, + business_name: { + type: 'string', + description: 'Business name shown to customers', + optional: true, + }, + business_email: { type: 'string', description: 'Email of the business', optional: true }, + description: { type: 'string', description: 'Description of the location', optional: true }, + capabilities: { + type: 'array', + description: 'Capabilities of the location (e.g. CREDIT_CARD_PROCESSING)', + optional: true, + items: { type: 'string' }, + }, + created_at: { + type: 'string', + description: 'Timestamp when the location was created (RFC 3339)', + optional: true, + }, +} as const satisfies Record + +export const LOCATION_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square Location object', + properties: LOCATION_OUTPUT_PROPERTIES, +} + +/** + * Output definition for a Square Order object. + * @see https://developer.squareup.com/reference/square/objects/Order + */ +export const ORDER_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Unique ID for the order' }, + location_id: { type: 'string', description: 'ID of the location for the order', optional: true }, + reference_id: { + type: 'string', + description: 'Optional external reference for the order', + optional: true, + }, + customer_id: { type: 'string', description: 'ID of the associated customer', optional: true }, + state: { + type: 'string', + description: 'Order state (OPEN, COMPLETED, or CANCELED)', + optional: true, + }, + version: { + type: 'number', + description: 'Optimistic concurrency version of the order', + optional: true, + }, + line_items: { + type: 'array', + description: 'Line items in the order', + optional: true, + items: { type: 'object' }, + }, + taxes: { + type: 'array', + description: 'Taxes applied to the order', + optional: true, + items: { type: 'object' }, + }, + discounts: { + type: 'array', + description: 'Discounts applied to the order', + optional: true, + items: { type: 'object' }, + }, + fulfillments: { + type: 'array', + description: 'Fulfillments for the order', + optional: true, + items: { type: 'object' }, + }, + net_amounts: { type: 'json', description: 'Net money amounts for the order', optional: true }, + total_money: MONEY_OUTPUT, + total_tax_money: MONEY_OUTPUT, + total_discount_money: MONEY_OUTPUT, + total_service_charge_money: MONEY_OUTPUT, + total_tip_money: MONEY_OUTPUT, + created_at: { + type: 'string', + description: 'Timestamp when the order was created (RFC 3339)', + optional: true, + }, + updated_at: { + type: 'string', + description: 'Timestamp when the order was last updated (RFC 3339)', + optional: true, + }, + closed_at: { + type: 'string', + description: 'Timestamp when the order was closed (RFC 3339)', + optional: true, + }, +} as const satisfies Record + +export const ORDER_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square Order object', + properties: ORDER_OUTPUT_PROPERTIES, +} + +export const ORDER_METADATA_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Square order ID' }, + state: { type: 'string', description: 'Current order state', optional: true }, + location_id: { type: 'string', description: 'Order location ID', optional: true }, +} as const satisfies Record + +/** + * Output definition for a Square Invoice object. + * @see https://developer.squareup.com/reference/square/objects/Invoice + */ +export const INVOICE_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Unique ID for the invoice' }, + version: { + type: 'number', + description: 'Optimistic concurrency version of the invoice', + optional: true, + }, + location_id: { + type: 'string', + description: 'ID of the location for the invoice', + optional: true, + }, + order_id: { + type: 'string', + description: 'ID of the order the invoice bills for', + optional: true, + }, + status: { + type: 'string', + description: 'Invoice status (DRAFT, UNPAID, SCHEDULED, PARTIALLY_PAID, PAID, etc.)', + optional: true, + }, + invoice_number: { type: 'string', description: 'Human-readable invoice number', optional: true }, + title: { type: 'string', description: 'Title of the invoice', optional: true }, + description: { type: 'string', description: 'Description of the invoice', optional: true }, + public_url: { + type: 'string', + description: 'URL where the customer can view and pay the invoice', + optional: true, + }, + primary_recipient: { + type: 'json', + description: 'Primary recipient of the invoice', + optional: true, + }, + payment_requests: { + type: 'array', + description: 'Payment requests for the invoice', + optional: true, + items: { type: 'object' }, + }, + next_payment_amount_money: MONEY_OUTPUT, + scheduled_at: { + type: 'string', + description: 'Timestamp when the invoice is scheduled to be sent (RFC 3339)', + optional: true, + }, + timezone: { type: 'string', description: 'Timezone used for invoice dates', optional: true }, + delivery_method: { + type: 'string', + description: 'How the invoice is delivered (EMAIL, SHARE_MANUALLY, SMS)', + optional: true, + }, + created_at: { + type: 'string', + description: 'Timestamp when the invoice was created (RFC 3339)', + optional: true, + }, + updated_at: { + type: 'string', + description: 'Timestamp when the invoice was last updated (RFC 3339)', + optional: true, + }, +} as const satisfies Record + +export const INVOICE_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square Invoice object', + properties: INVOICE_OUTPUT_PROPERTIES, +} + +export const INVOICE_METADATA_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Square invoice ID' }, + status: { type: 'string', description: 'Current invoice status', optional: true }, + version: { type: 'number', description: 'Invoice version', optional: true }, +} as const satisfies Record + +/** + * Output definition for a Square CatalogObject. + * Catalog objects are polymorphic; type-specific data lives in `*_data` fields. + * @see https://developer.squareup.com/reference/square/objects/CatalogObject + */ +export const CATALOG_OBJECT_OUTPUT_PROPERTIES = { + type: { + type: 'string', + description: 'Type of catalog object (ITEM, ITEM_VARIATION, CATEGORY, IMAGE, etc.)', + }, + id: { type: 'string', description: 'Unique ID for the catalog object' }, + version: { + type: 'number', + description: 'Optimistic concurrency version of the object', + optional: true, + }, + updated_at: { + type: 'string', + description: 'Timestamp when the object was last updated (RFC 3339)', + optional: true, + }, + is_deleted: { type: 'boolean', description: 'Whether the object is deleted', optional: true }, + present_at_all_locations: { + type: 'boolean', + description: 'Whether the object is present at all locations', + optional: true, + }, + item_data: { + type: 'json', + description: 'Item-specific data (when type is ITEM)', + optional: true, + }, + item_variation_data: { + type: 'json', + description: 'Variation-specific data (when type is ITEM_VARIATION)', + optional: true, + }, + category_data: { + type: 'json', + description: 'Category-specific data (when type is CATEGORY)', + optional: true, + }, + image_data: { + type: 'json', + description: 'Image-specific data (when type is IMAGE)', + optional: true, + }, +} as const satisfies Record + +export const CATALOG_OBJECT_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square CatalogObject', + properties: CATALOG_OBJECT_OUTPUT_PROPERTIES, +} + +export const CATALOG_OBJECT_METADATA_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Square catalog object ID' }, + type: { type: 'string', description: 'Catalog object type', optional: true }, + version: { type: 'number', description: 'Catalog object version', optional: true }, +} as const satisfies Record + +/** + * Output definition for a Square InventoryCount object. + * @see https://developer.squareup.com/reference/square/objects/InventoryCount + */ +export const INVENTORY_COUNT_OUTPUT_PROPERTIES = { + catalog_object_id: { + type: 'string', + description: 'ID of the catalog object (item variation) being counted', + optional: true, + }, + catalog_object_type: { + type: 'string', + description: 'Type of the counted catalog object (usually ITEM_VARIATION)', + optional: true, + }, + state: { + type: 'string', + description: 'Inventory state (e.g. IN_STOCK, SOLD, WASTE)', + optional: true, + }, + location_id: { type: 'string', description: 'ID of the location for this count', optional: true }, + quantity: { + type: 'string', + description: 'Number of units in the given state at the location', + optional: true, + }, + calculated_at: { + type: 'string', + description: 'Timestamp when the count was calculated (RFC 3339)', + optional: true, + }, +} as const satisfies Record + +export const INVENTORY_COUNT_OUTPUT: OutputProperty = { + type: 'object', + description: 'Square InventoryCount object', + properties: INVENTORY_COUNT_OUTPUT_PROPERTIES, +} + +/** + * Pagination metadata for cursor-paged Square list/search endpoints. + */ +export const LIST_METADATA_OUTPUT_PROPERTIES = { + count: { type: 'number', description: 'Number of items returned in this page' }, + cursor: { + type: 'string', + description: 'Pagination cursor to fetch the next page, if more results exist', + optional: true, + }, +} as const satisfies Record + +export const LIST_METADATA_OUTPUT: OutputProperty = { + type: 'object', + description: 'List pagination metadata', + properties: LIST_METADATA_OUTPUT_PROPERTIES, +} + +interface SquareMoney { + amount?: number + currency?: string +} + +interface SquareAddress { + address_line_1?: string + address_line_2?: string + locality?: string + administrative_district_level_1?: string + postal_code?: string + country?: string + [key: string]: unknown +} + +interface SquareListMetadata { + count: number + cursor?: string +} + +interface PaymentObject { + id: string + status?: string + amount_money?: SquareMoney + order_id?: string + created_at: string + [key: string]: unknown +} + +interface RefundObject { + id: string + status?: string + amount_money?: SquareMoney + payment_id?: string + created_at: string + [key: string]: unknown +} + +interface CustomerObject { + id: string + given_name?: string + family_name?: string + email_address?: string + created_at: string + [key: string]: unknown +} + +interface LocationObject { + id: string + name?: string + [key: string]: unknown +} + +interface OrderObject { + id: string + state?: string + location_id?: string + [key: string]: unknown +} + +interface InvoiceObject { + id: string + status?: string + version?: number + [key: string]: unknown +} + +interface CatalogObject { + id: string + type: string + version?: number + [key: string]: unknown +} + +interface InventoryCountObject { + catalog_object_id?: string + catalog_object_type?: string + state?: string + location_id?: string + quantity?: string + calculated_at?: string + [key: string]: unknown +} + +export interface CreatePaymentParams { + apiKey: string + sourceId: string + amount: number + currency: string + idempotencyKey?: string + customerId?: string + locationId?: string + orderId?: string + referenceId?: string + note?: string + autocomplete?: boolean +} + +export interface GetPaymentParams { + apiKey: string + paymentId: string +} + +export interface ListPaymentsParams { + apiKey: string + locationId?: string + beginTime?: string + endTime?: string + limit?: number + cursor?: string +} + +export interface RefundPaymentParams { + apiKey: string + paymentId: string + amount: number + currency: string + idempotencyKey?: string + reason?: string +} + +export interface CreateCustomerParams { + apiKey: string + givenName?: string + familyName?: string + companyName?: string + emailAddress?: string + phoneNumber?: string + note?: string + referenceId?: string + address?: SquareAddress + idempotencyKey?: string +} + +export interface GetCustomerParams { + apiKey: string + customerId: string +} + +export interface ListCustomersParams { + apiKey: string + limit?: number + cursor?: string + sortField?: string + sortOrder?: string +} + +export interface SearchCustomersParams { + apiKey: string + query?: Record + limit?: number + cursor?: string +} + +export interface UpdateCustomerParams { + apiKey: string + customerId: string + givenName?: string + familyName?: string + companyName?: string + emailAddress?: string + phoneNumber?: string + note?: string + referenceId?: string + address?: SquareAddress +} + +export interface DeleteCustomerParams { + apiKey: string + customerId: string +} + +export interface ListLocationsParams { + apiKey: string +} + +export interface CreateOrderParams { + apiKey: string + order: Record + idempotencyKey?: string +} + +export interface GetOrderParams { + apiKey: string + orderId: string +} + +export interface SearchOrdersParams { + apiKey: string + locationIds: string[] + query?: Record + limit?: number + cursor?: string +} + +export interface CreateInvoiceParams { + apiKey: string + invoice: Record + idempotencyKey?: string +} + +export interface GetInvoiceParams { + apiKey: string + invoiceId: string +} + +export interface ListInvoicesParams { + apiKey: string + locationId: string + limit?: number + cursor?: string +} + +export interface PublishInvoiceParams { + apiKey: string + invoiceId: string + version: number + idempotencyKey?: string +} + +export interface UpsertCatalogObjectParams { + apiKey: string + object: Record + idempotencyKey?: string +} + +export interface GetCatalogObjectParams { + apiKey: string + objectId: string + includeRelatedObjects?: boolean +} + +export interface ListCatalogParams { + apiKey: string + types?: string + cursor?: string +} + +export interface SearchCatalogObjectsParams { + apiKey: string + objectTypes?: string[] + query?: Record + limit?: number + cursor?: string +} + +export interface CreateCatalogImageParams { + apiKey: string + file?: unknown + fileContent?: string + fileName?: string + objectId?: string + caption?: string + idempotencyKey?: string +} + +export interface CancelPaymentParams { + apiKey: string + paymentId: string +} + +export interface CompletePaymentParams { + apiKey: string + paymentId: string +} + +export interface GetRefundParams { + apiKey: string + refundId: string +} + +export interface ListRefundsParams { + apiKey: string + locationId?: string + status?: string + beginTime?: string + endTime?: string + limit?: number + cursor?: string +} + +export interface PayOrderParams { + apiKey: string + orderId: string + orderVersion?: number + paymentIds?: string[] + idempotencyKey?: string +} + +export interface SearchInvoicesParams { + apiKey: string + locationIds: string[] + limit?: number + cursor?: string +} + +export interface CancelInvoiceParams { + apiKey: string + invoiceId: string + version: number +} + +export interface DeleteInvoiceParams { + apiKey: string + invoiceId: string + version?: number +} + +export interface DeleteCatalogObjectParams { + apiKey: string + objectId: string +} + +export interface GetLocationParams { + apiKey: string + locationId: string +} + +export interface BatchRetrieveInventoryCountsParams { + apiKey: string + catalogObjectIds?: string[] + locationIds?: string[] + cursor?: string +} + +export interface PaymentResponse extends ToolResponse { + output: { + payment: PaymentObject + metadata: { id: string; status?: string; order_id?: string } + } +} + +export interface PaymentListResponse extends ToolResponse { + output: { + payments: PaymentObject[] + metadata: SquareListMetadata + } +} + +export interface RefundResponse extends ToolResponse { + output: { + refund: RefundObject + metadata: { id: string; status?: string; payment_id?: string } + } +} + +export interface CustomerResponse extends ToolResponse { + output: { + customer: CustomerObject + metadata: { id: string; email_address?: string; given_name?: string; family_name?: string } + } +} + +export interface CustomerListResponse extends ToolResponse { + output: { + customers: CustomerObject[] + metadata: SquareListMetadata + } +} + +export interface CustomerDeleteResponse extends ToolResponse { + output: { + deleted: boolean + id: string + } +} + +export interface LocationListResponse extends ToolResponse { + output: { + locations: LocationObject[] + metadata: { count: number } + } +} + +export interface OrderResponse extends ToolResponse { + output: { + order: OrderObject + metadata: { id: string; state?: string; location_id?: string } + } +} + +export interface OrderListResponse extends ToolResponse { + output: { + orders: OrderObject[] + metadata: SquareListMetadata + } +} + +export interface InvoiceResponse extends ToolResponse { + output: { + invoice: InvoiceObject + metadata: { id: string; status?: string; version?: number } + } +} + +export interface InvoiceListResponse extends ToolResponse { + output: { + invoices: InvoiceObject[] + metadata: SquareListMetadata + } +} + +export interface CatalogObjectResponse extends ToolResponse { + output: { + object: CatalogObject + metadata: { id: string; type?: string; version?: number } + } +} + +export interface CatalogListResponse extends ToolResponse { + output: { + objects: CatalogObject[] + metadata: SquareListMetadata + } +} + +export interface RefundListResponse extends ToolResponse { + output: { + refunds: RefundObject[] + metadata: SquareListMetadata + } +} + +export interface LocationResponse extends ToolResponse { + output: { + location: LocationObject + metadata: { id: string; name?: string } + } +} + +export interface InvoiceDeleteResponse extends ToolResponse { + output: { + deleted: boolean + id: string + } +} + +export interface CatalogDeleteResponse extends ToolResponse { + output: { + deleted: boolean + deleted_object_ids: string[] + deleted_at: string | null + } +} + +export interface InventoryCountListResponse extends ToolResponse { + output: { + counts: InventoryCountObject[] + metadata: SquareListMetadata + } +} + +export type SquareResponse = + | PaymentResponse + | PaymentListResponse + | RefundResponse + | RefundListResponse + | CustomerResponse + | CustomerListResponse + | CustomerDeleteResponse + | LocationListResponse + | LocationResponse + | OrderResponse + | OrderListResponse + | InvoiceResponse + | InvoiceListResponse + | InvoiceDeleteResponse + | CatalogObjectResponse + | CatalogListResponse + | CatalogDeleteResponse + | InventoryCountListResponse diff --git a/apps/sim/tools/square/update_customer.ts b/apps/sim/tools/square/update_customer.ts new file mode 100644 index 00000000000..1ba1bff2599 --- /dev/null +++ b/apps/sim/tools/square/update_customer.ts @@ -0,0 +1,124 @@ +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CustomerResponse, UpdateCustomerParams } from '@/tools/square/types' +import { + CUSTOMER_METADATA_OUTPUT_PROPERTIES, + CUSTOMER_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareUpdateCustomerTool: ToolConfig = { + id: 'square_update_customer', + name: 'Square Update Customer', + description: 'Update fields on an existing customer profile', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + customerId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ID of the customer to update', + }, + givenName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'First name of the customer', + }, + familyName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Last name of the customer', + }, + companyName: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Business name of the customer', + }, + emailAddress: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Email address of the customer', + }, + phoneNumber: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Phone number of the customer', + }, + note: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Note about the customer', + }, + referenceId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional external reference for the customer', + }, + address: { + type: 'json', + required: false, + visibility: 'user-or-llm', + description: 'Square address object for the customer', + }, + }, + + request: { + url: (params) => `${SQUARE_BASE_URL}/v2/customers/${encodeURIComponent(params.customerId)}`, + method: 'PUT', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => { + const body: Record = {} + if (params.givenName !== undefined) body.given_name = params.givenName + if (params.familyName !== undefined) body.family_name = params.familyName + if (params.companyName !== undefined) body.company_name = params.companyName + if (params.emailAddress !== undefined) body.email_address = params.emailAddress + if (params.phoneNumber !== undefined) body.phone_number = params.phoneNumber + if (params.note !== undefined) body.note = params.note + if (params.referenceId !== undefined) body.reference_id = params.referenceId + if (params.address !== undefined) body.address = params.address + return body + }, + }, + + transformResponse: async (response) => { + const data = await response.json() + const customer = data.customer ?? {} + return { + success: true, + output: { + customer, + metadata: { + id: customer.id, + email_address: customer.email_address ?? null, + given_name: customer.given_name ?? null, + family_name: customer.family_name ?? null, + }, + }, + } + }, + + outputs: { + customer: { ...CUSTOMER_OUTPUT, description: 'The updated customer object' }, + metadata: { + type: 'json', + description: 'Customer summary metadata', + properties: CUSTOMER_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/apps/sim/tools/square/upsert_catalog_object.ts b/apps/sim/tools/square/upsert_catalog_object.ts new file mode 100644 index 00000000000..69d3731da50 --- /dev/null +++ b/apps/sim/tools/square/upsert_catalog_object.ts @@ -0,0 +1,78 @@ +import { generateId } from '@sim/utils/id' +import { ErrorExtractorId } from '@/tools/error-extractors' +import type { CatalogObjectResponse, UpsertCatalogObjectParams } from '@/tools/square/types' +import { + CATALOG_OBJECT_METADATA_OUTPUT_PROPERTIES, + CATALOG_OBJECT_OUTPUT, + SQUARE_BASE_URL, + squareHeaders, +} from '@/tools/square/types' +import type { ToolConfig } from '@/tools/types' + +export const squareUpsertCatalogObjectTool: ToolConfig< + UpsertCatalogObjectParams, + CatalogObjectResponse +> = { + id: 'square_upsert_catalog_object', + name: 'Square Upsert Catalog Object', + description: 'Create or update a catalog object such as an item, variation, or category', + version: '1.0.0', + errorExtractor: ErrorExtractorId.SQUARE_ERRORS, + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Square access token (personal access token)', + }, + object: { + type: 'json', + required: true, + visibility: 'user-or-llm', + description: + 'Square catalog object to create or update. Use ID "#name" for new objects (e.g. {"type":"ITEM","id":"#Coffee","item_data":{"name":"Coffee"}})', + }, + idempotencyKey: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Unique key to make the request idempotent (auto-generated if omitted)', + }, + }, + + request: { + url: () => `${SQUARE_BASE_URL}/v2/catalog/object`, + method: 'POST', + headers: (params) => squareHeaders(params.apiKey), + body: (params) => ({ + idempotency_key: params.idempotencyKey || generateId(), + object: params.object, + }), + }, + + transformResponse: async (response) => { + const data = await response.json() + const object = data.catalog_object ?? {} + return { + success: true, + output: { + object, + metadata: { + id: object.id, + type: object.type ?? null, + version: object.version ?? null, + }, + }, + } + }, + + outputs: { + object: { ...CATALOG_OBJECT_OUTPUT, description: 'The created or updated catalog object' }, + metadata: { + type: 'json', + description: 'Catalog object summary metadata', + properties: CATALOG_OBJECT_METADATA_OUTPUT_PROPERTIES, + }, + }, +} diff --git a/scripts/check-api-validation-contracts.ts b/scripts/check-api-validation-contracts.ts index ed468073fe8..2ca18013904 100644 --- a/scripts/check-api-validation-contracts.ts +++ b/scripts/check-api-validation-contracts.ts @@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries') const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors') const BASELINE = { - totalRoutes: 826, - zodRoutes: 826, + totalRoutes: 827, + zodRoutes: 827, nonZodRoutes: 0, } as const From 81d510748e8a8f8dfdd54488f1ad42149f351c73 Mon Sep 17 00:00:00 2001 From: waleed Date: Sun, 14 Jun 2026 23:42:03 -0700 Subject: [PATCH 2/7] fix(square): correct catalog image part name and address review feedback - Fix catalog image upload: Square's multipart part for the binary is `file`, not `image_file` (per the live API cURL examples); this would have caused upload failures - Catalog image route: check response.ok before parsing, drop the unreachable legacy base64 path, derive MIME from the uploaded file - Block: split the search query field per operation so placeholders match each endpoint's schema; parse each JSON field individually so errors name the field - Round out coverage: complete_payment version_token; customer nickname/birthday; batch inventory states/updated_after/limit --- .../content/docs/en/integrations/square.mdx | 11 +- .../api/tools/square/catalog-image/route.ts | 70 ++++----- apps/sim/blocks/blocks/square.ts | 148 ++++++++++++++---- apps/sim/lib/api/contracts/tools/square.ts | 1 - .../square/batch_retrieve_inventory_counts.ts | 21 +++ apps/sim/tools/square/complete_payment.ts | 8 +- apps/sim/tools/square/create_catalog_image.ts | 9 +- apps/sim/tools/square/create_customer.ts | 14 ++ apps/sim/tools/square/types.ts | 9 +- apps/sim/tools/square/update_customer.ts | 14 ++ 10 files changed, 227 insertions(+), 78 deletions(-) diff --git a/apps/docs/content/docs/en/integrations/square.mdx b/apps/docs/content/docs/en/integrations/square.mdx index 457f42e1843..73c60e96f5f 100644 --- a/apps/docs/content/docs/en/integrations/square.mdx +++ b/apps/docs/content/docs/en/integrations/square.mdx @@ -260,6 +260,7 @@ Capture (complete) a payment that was authorized with delayed capture | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Square access token \(personal access token\) | | `paymentId` | string | Yes | ID of the payment to complete | +| `versionToken` | string | No | Optional version token for optimistic concurrency control | #### Output @@ -424,8 +425,10 @@ Create a new customer profile in the Square customer directory | `givenName` | string | No | First name of the customer | | `familyName` | string | No | Last name of the customer | | `companyName` | string | No | Business name of the customer | +| `nickname` | string | No | Nickname of the customer | | `emailAddress` | string | No | Email address of the customer | | `phoneNumber` | string | No | Phone number of the customer | +| `birthday` | string | No | Birthday in YYYY-MM-DD or MM-DD format | | `note` | string | No | Note about the customer | | `referenceId` | string | No | Optional external reference for the customer | | `address` | json | No | Square address object for the customer | @@ -634,8 +637,10 @@ Update fields on an existing customer profile | `givenName` | string | No | First name of the customer | | `familyName` | string | No | Last name of the customer | | `companyName` | string | No | Business name of the customer | +| `nickname` | string | No | Nickname of the customer | | `emailAddress` | string | No | Email address of the customer | | `phoneNumber` | string | No | Phone number of the customer | +| `birthday` | string | No | Birthday in YYYY-MM-DD or MM-DD format | | `note` | string | No | Note about the customer | | `referenceId` | string | No | Optional external reference for the customer | | `address` | json | No | Square address object for the customer | @@ -1395,8 +1400,7 @@ Upload an image and attach it to the catalog, optionally to a specific item | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Square access token \(personal access token\) | -| `file` | file | No | The image file to upload \(UserFile object\) | -| `fileContent` | string | No | Legacy: base64 encoded image content | +| `file` | file | Yes | The image file to upload \(UserFile object\) | | `fileName` | string | No | Optional filename override for the image | | `objectId` | string | No | ID of the catalog object \(e.g. an item\) to attach the image to | | `caption` | string | No | Caption \(alt text\) for the image | @@ -1452,6 +1456,9 @@ Retrieve current inventory counts for catalog items across locations | `apiKey` | string | Yes | Square access token \(personal access token\) | | `catalogObjectIds` | array | No | IDs of the catalog item variations to retrieve counts for | | `locationIds` | array | No | IDs of the locations to retrieve counts for \(defaults to all locations\) | +| `states` | array | No | Inventory states to filter by \(e.g. IN_STOCK, SOLD, IN_TRANSIT\) | +| `updatedAfter` | string | No | Only return counts updated after this RFC 3339 timestamp | +| `limit` | number | No | Maximum number of results to return per page \(1-1000\) | | `cursor` | string | No | Pagination cursor from a previous response | #### Output diff --git a/apps/sim/app/api/tools/square/catalog-image/route.ts b/apps/sim/app/api/tools/square/catalog-image/route.ts index fa35366cf48..622c5c1c7a2 100644 --- a/apps/sim/app/api/tools/square/catalog-image/route.ts +++ b/apps/sim/app/api/tools/square/catalog-image/route.ts @@ -34,35 +34,28 @@ export const POST = withRouteHandler(async (request: NextRequest) => { if (!parsed.success) return parsed.response const validatedData = parsed.data.body - let fileBuffer: Buffer - let fileName: string - let mimeType = 'application/octet-stream' - - if (validatedData.file) { - const userFiles = processFilesToUserFiles( - [validatedData.file as RawFileInput], - requestId, - logger - ) + if (!validatedData.file) { + return NextResponse.json({ success: false, error: 'File is required' }, { status: 400 }) + } - if (userFiles.length === 0) { - return NextResponse.json({ success: false, error: 'Invalid file input' }, { status: 400 }) - } + const userFiles = processFilesToUserFiles( + [validatedData.file as RawFileInput], + requestId, + logger + ) - const userFile = userFiles[0] - const denied = await assertToolFileAccess(userFile.key, authResult.userId, requestId, logger) - if (denied) return denied - - fileBuffer = await downloadFileFromStorage(userFile, requestId, logger) - fileName = validatedData.fileName || userFile.name - if (userFile.type) mimeType = userFile.type - } else if (validatedData.fileContent) { - fileBuffer = Buffer.from(validatedData.fileContent, 'base64') - fileName = validatedData.fileName || 'image' - } else { - return NextResponse.json({ success: false, error: 'File is required' }, { status: 400 }) + if (userFiles.length === 0) { + return NextResponse.json({ success: false, error: 'Invalid file input' }, { status: 400 }) } + const userFile = userFiles[0] + const denied = await assertToolFileAccess(userFile.key, authResult.userId, requestId, logger) + if (denied) return denied + + const fileBuffer = await downloadFileFromStorage(userFile, requestId, logger) + const fileName = validatedData.fileName || userFile.name + const mimeType = userFile.type || 'application/octet-stream' + const imageRequest: Record = { idempotency_key: validatedData.idempotencyKey || generateId(), image: { @@ -75,11 +68,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => { const formData = new FormData() formData.append('request', JSON.stringify(imageRequest)) - formData.append( - 'image_file', - new Blob([new Uint8Array(fileBuffer)], { type: mimeType }), - fileName - ) + formData.append('file', new Blob([new Uint8Array(fileBuffer)], { type: mimeType }), fileName) const response = await fetch(`${SQUARE_BASE_URL}/v2/catalog/images`, { method: 'POST', @@ -90,14 +79,25 @@ export const POST = withRouteHandler(async (request: NextRequest) => { body: formData, }) - const data = await response.json() - if (!response.ok) { - const errorMessage = data?.errors?.[0]?.detail || 'Failed to upload catalog image' - logger.error(`[${requestId}] Square API error:`, { status: response.status, data }) - return NextResponse.json({ success: false, error: errorMessage }, { status: response.status }) + const errorText = await response.text() + let detail: string | undefined + try { + detail = JSON.parse(errorText)?.errors?.[0]?.detail + } catch { + detail = undefined + } + logger.error(`[${requestId}] Square API error:`, { status: response.status, body: errorText }) + return NextResponse.json( + { + success: false, + error: detail || `Failed to upload catalog image (HTTP ${response.status})`, + }, + { status: response.status } + ) } + const data = await response.json() const object = data.image ?? {} return NextResponse.json({ diff --git a/apps/sim/blocks/blocks/square.ts b/apps/sim/blocks/blocks/square.ts index ac134f30cb2..157c276fcde 100644 --- a/apps/sim/blocks/blocks/square.ts +++ b/apps/sim/blocks/blocks/square.ts @@ -139,6 +139,14 @@ export const SquareBlock: BlockConfig = { placeholder: 'Reason for the refund', condition: { field: 'operation', value: 'refund_payment' }, }, + { + id: 'versionToken', + title: 'Version Token', + type: 'short-input', + placeholder: 'Optional version token for concurrency control', + condition: { field: 'operation', value: 'complete_payment' }, + mode: 'advanced', + }, { id: 'autocomplete', title: 'Capture Immediately', @@ -214,6 +222,14 @@ export const SquareBlock: BlockConfig = { condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, mode: 'advanced', }, + { + id: 'nickname', + title: 'Nickname', + type: 'short-input', + placeholder: 'Customer nickname', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + mode: 'advanced', + }, { id: 'emailAddress', title: 'Email Address', @@ -229,6 +245,14 @@ export const SquareBlock: BlockConfig = { condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, mode: 'advanced', }, + { + id: 'birthday', + title: 'Birthday', + type: 'short-input', + placeholder: 'YYYY-MM-DD or MM-DD', + condition: { field: 'operation', value: ['create_customer', 'update_customer'] }, + mode: 'advanced', + }, { id: 'address', title: 'Address (JSON)', @@ -285,22 +309,54 @@ export const SquareBlock: BlockConfig = { mode: 'advanced', }, - // Search query (customers / orders / catalog) + // Search query — one field per search operation so the placeholder and wand + // prompt match each endpoint's distinct query schema. All map to the same + // canonical `query` param. { - id: 'query', + id: 'queryCustomers', title: 'Query (JSON)', type: 'code', language: 'json', + canonicalParamId: 'query', placeholder: '{"filter": {"email_address": {"exact": "customer@example.com"}}}', - condition: { - field: 'operation', - value: ['search_customers', 'search_orders', 'search_catalog_objects'], + condition: { field: 'operation', value: 'search_customers' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate a Square SearchCustomers query JSON object with a filter and optional sort. Return ONLY the JSON object.', + generationType: 'json-object', + }, + }, + { + id: 'queryOrders', + title: 'Query (JSON)', + type: 'code', + language: 'json', + canonicalParamId: 'query', + placeholder: '{"filter": {"state_filter": {"states": ["OPEN"]}}}', + condition: { field: 'operation', value: 'search_orders' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: + 'Generate a Square SearchOrders query JSON object with a filter (e.g. state_filter, date_time_filter) and optional sort. Return ONLY the JSON object.', + generationType: 'json-object', }, + }, + { + id: 'queryCatalog', + title: 'Query (JSON)', + type: 'code', + language: 'json', + canonicalParamId: 'query', + placeholder: '{"text_query": {"keywords": ["coffee"]}}', + condition: { field: 'operation', value: 'search_catalog_objects' }, mode: 'advanced', wandConfig: { enabled: true, prompt: - 'Generate a Square search query JSON object for the given operation. Return ONLY the JSON object.', + 'Generate a Square SearchCatalogObjects query JSON object (e.g. text_query, prefix_query, exact_query). Return ONLY the JSON object.', generationType: 'json-object', }, }, @@ -439,6 +495,28 @@ export const SquareBlock: BlockConfig = { condition: { field: 'operation', value: 'batch_retrieve_inventory_counts' }, mode: 'advanced', }, + { + id: 'states', + title: 'Inventory States (JSON Array)', + type: 'code', + language: 'json', + placeholder: '["IN_STOCK", "SOLD"]', + condition: { field: 'operation', value: 'batch_retrieve_inventory_counts' }, + mode: 'advanced', + }, + { + id: 'updatedAfter', + title: 'Updated After', + type: 'short-input', + placeholder: 'RFC 3339 timestamp', + condition: { field: 'operation', value: 'batch_retrieve_inventory_counts' }, + mode: 'advanced', + wandConfig: { + enabled: true, + prompt: 'Generate an RFC 3339 timestamp. Return ONLY the timestamp string.', + generationType: 'timestamp', + }, + }, { id: 'includeRelatedObjects', title: 'Include Related Objects', @@ -535,6 +613,7 @@ export const SquareBlock: BlockConfig = { 'list_invoices', 'search_invoices', 'search_catalog_objects', + 'batch_retrieve_inventory_counts', ], }, mode: 'advanced', @@ -639,6 +718,7 @@ export const SquareBlock: BlockConfig = { objectTypes, paymentIds, catalogObjectIds, + states, amount, limit, version, @@ -651,32 +731,31 @@ export const SquareBlock: BlockConfig = { // Normalize the catalog image file from basic (uploadFile) or advanced (fileRef) const normalizedFile = normalizeFileInput(uploadFile || fileRef, { single: true }) - // Parse JSON-typed inputs - let parsedAddress: unknown - let parsedQuery: unknown - let parsedOrder: unknown - let parsedInvoice: unknown - let parsedObject: unknown - let parsedLocationIds: unknown - let parsedObjectTypes: unknown - let parsedPaymentIds: unknown - let parsedCatalogObjectIds: unknown - try { - if (address) parsedAddress = JSON.parse(address) - if (query) parsedQuery = JSON.parse(query) - if (order) parsedOrder = JSON.parse(order) - if (invoice) parsedInvoice = JSON.parse(invoice) - if (object) parsedObject = JSON.parse(object) - if (locationIds) parsedLocationIds = JSON.parse(locationIds) - if (objectTypes) parsedObjectTypes = JSON.parse(objectTypes) - if (paymentIds) parsedPaymentIds = JSON.parse(paymentIds) - if (catalogObjectIds) parsedCatalogObjectIds = JSON.parse(catalogObjectIds) - } catch (error) { - throw new Error( - `Invalid JSON input: ${error instanceof Error ? error.message : 'unknown error'}` - ) + // Parse a JSON-typed input, naming the field in any error so the user + // knows exactly which input to fix. + const parseJsonField = (value: unknown, field: string): unknown => { + if (value === undefined || value === null || value === '') return undefined + if (typeof value !== 'string') return value + try { + return JSON.parse(value) + } catch (error) { + throw new Error( + `Invalid JSON in "${field}": ${error instanceof Error ? error.message : 'unknown error'}` + ) + } } + const parsedAddress = parseJsonField(address, 'address') + const parsedQuery = parseJsonField(query, 'query') + const parsedOrder = parseJsonField(order, 'order') + const parsedInvoice = parseJsonField(invoice, 'invoice') + const parsedObject = parseJsonField(object, 'object') + const parsedLocationIds = parseJsonField(locationIds, 'locationIds') + const parsedObjectTypes = parseJsonField(objectTypes, 'objectTypes') + const parsedPaymentIds = parseJsonField(paymentIds, 'paymentIds') + const parsedCatalogObjectIds = parseJsonField(catalogObjectIds, 'catalogObjectIds') + const parsedStates = parseJsonField(states, 'states') + return { ...rest, ...(normalizedFile && { file: normalizedFile }), @@ -689,6 +768,7 @@ export const SquareBlock: BlockConfig = { ...(parsedObjectTypes !== undefined && { objectTypes: parsedObjectTypes }), ...(parsedPaymentIds !== undefined && { paymentIds: parsedPaymentIds }), ...(parsedCatalogObjectIds !== undefined && { catalogObjectIds: parsedCatalogObjectIds }), + ...(parsedStates !== undefined && { states: parsedStates }), ...(amount !== undefined && amount !== '' && { amount: Number(amount) }), ...(limit !== undefined && limit !== '' && { limit: Number(limit) }), ...(version !== undefined && version !== '' && { version: Number(version) }), @@ -713,6 +793,7 @@ export const SquareBlock: BlockConfig = { amount: { type: 'number', description: 'Amount in smallest currency denomination' }, currency: { type: 'string', description: 'ISO 4217 currency code' }, reason: { type: 'string', description: 'Refund reason' }, + versionToken: { type: 'string', description: 'Version token for payment concurrency control' }, autocomplete: { type: 'boolean', description: 'Capture payment immediately' }, beginTime: { type: 'string', description: 'Start of the reporting period (RFC 3339)' }, endTime: { type: 'string', description: 'End of the reporting period (RFC 3339)' }, @@ -720,8 +801,10 @@ export const SquareBlock: BlockConfig = { givenName: { type: 'string', description: 'Customer first name' }, familyName: { type: 'string', description: 'Customer last name' }, companyName: { type: 'string', description: 'Customer company name' }, + nickname: { type: 'string', description: 'Customer nickname' }, emailAddress: { type: 'string', description: 'Customer email address' }, phoneNumber: { type: 'string', description: 'Customer phone number' }, + birthday: { type: 'string', description: 'Customer birthday (YYYY-MM-DD or MM-DD)' }, address: { type: 'json', description: 'Customer address object' }, note: { type: 'string', description: 'Note' }, referenceId: { type: 'string', description: 'External reference ID' }, @@ -742,6 +825,11 @@ export const SquareBlock: BlockConfig = { types: { type: 'string', description: 'Comma-separated catalog object types' }, objectTypes: { type: 'json', description: 'Array of catalog object types to search' }, catalogObjectIds: { type: 'json', description: 'Array of catalog object IDs for inventory' }, + states: { type: 'json', description: 'Array of inventory states to filter by' }, + updatedAfter: { + type: 'string', + description: 'Only return inventory counts updated after this time', + }, file: { type: 'json', description: 'Image file to upload (canonical param)' }, fileName: { type: 'string', description: 'Filename override for the image' }, caption: { type: 'string', description: 'Image caption' }, diff --git a/apps/sim/lib/api/contracts/tools/square.ts b/apps/sim/lib/api/contracts/tools/square.ts index 283195ea172..8be19a863cd 100644 --- a/apps/sim/lib/api/contracts/tools/square.ts +++ b/apps/sim/lib/api/contracts/tools/square.ts @@ -28,7 +28,6 @@ const squareCatalogImageResponseSchema = z.object({ export const squareCatalogImageBodySchema = z.object({ accessToken: z.string().min(1, 'Access token is required'), file: FileInputSchema.optional().nullable(), - fileContent: z.string().optional().nullable(), fileName: z.string().optional().nullable(), objectId: z.string().optional().nullable(), caption: z.string().optional().nullable(), diff --git a/apps/sim/tools/square/batch_retrieve_inventory_counts.ts b/apps/sim/tools/square/batch_retrieve_inventory_counts.ts index d9779d8f127..686db627463 100644 --- a/apps/sim/tools/square/batch_retrieve_inventory_counts.ts +++ b/apps/sim/tools/square/batch_retrieve_inventory_counts.ts @@ -40,6 +40,24 @@ export const squareBatchRetrieveInventoryCountsTool: ToolConfig< visibility: 'user-or-llm', description: 'IDs of the locations to retrieve counts for (defaults to all locations)', }, + states: { + type: 'array', + required: false, + visibility: 'user-or-llm', + description: 'Inventory states to filter by (e.g. IN_STOCK, SOLD, IN_TRANSIT)', + }, + updatedAfter: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Only return counts updated after this RFC 3339 timestamp', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of results to return per page (1-1000)', + }, cursor: { type: 'string', required: false, @@ -56,6 +74,9 @@ export const squareBatchRetrieveInventoryCountsTool: ToolConfig< const body: Record = {} if (params.catalogObjectIds) body.catalog_object_ids = params.catalogObjectIds if (params.locationIds) body.location_ids = params.locationIds + if (params.states) body.states = params.states + if (params.updatedAfter) body.updated_after = params.updatedAfter + if (params.limit !== undefined) body.limit = params.limit if (params.cursor) body.cursor = params.cursor return body }, diff --git a/apps/sim/tools/square/complete_payment.ts b/apps/sim/tools/square/complete_payment.ts index 7216a40b9c6..6d70634ba4c 100644 --- a/apps/sim/tools/square/complete_payment.ts +++ b/apps/sim/tools/square/complete_payment.ts @@ -28,6 +28,12 @@ export const squareCompletePaymentTool: ToolConfig squareHeaders(params.apiKey), - body: () => ({}), + body: (params) => (params.versionToken ? { version_token: params.versionToken } : {}), }, transformResponse: async (response) => { diff --git a/apps/sim/tools/square/create_catalog_image.ts b/apps/sim/tools/square/create_catalog_image.ts index 8c8fc8dc135..10be9b47fdc 100644 --- a/apps/sim/tools/square/create_catalog_image.ts +++ b/apps/sim/tools/square/create_catalog_image.ts @@ -23,16 +23,10 @@ export const squareCreateCatalogImageTool: ToolConfig< }, file: { type: 'file', - required: false, + required: true, visibility: 'user-or-llm', description: 'The image file to upload (UserFile object)', }, - fileContent: { - type: 'string', - required: false, - visibility: 'hidden', - description: 'Legacy: base64 encoded image content', - }, fileName: { type: 'string', required: false, @@ -68,7 +62,6 @@ export const squareCreateCatalogImageTool: ToolConfig< body: (params) => ({ accessToken: params.apiKey, file: params.file, - fileContent: params.fileContent, fileName: params.fileName, objectId: params.objectId, caption: params.caption, diff --git a/apps/sim/tools/square/create_customer.ts b/apps/sim/tools/square/create_customer.ts index a6ab2a51275..787ab46ddbf 100644 --- a/apps/sim/tools/square/create_customer.ts +++ b/apps/sim/tools/square/create_customer.ts @@ -41,6 +41,12 @@ export const squareCreateCustomerTool: ToolConfig Date: Mon, 15 Jun 2026 00:01:50 -0700 Subject: [PATCH 3/7] fix(square): correct canonical file param usage and revert query split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Read the catalog image file from the canonical `params.file` (the basic/advanced inputs are collapsed before the params function runs) instead of the raw uploadFile/fileRef ids, which no longer exist at that point — fixes the Canonical Param Validation test and a latent upload bug - Revert the per-operation query split: canonicalParamId is only valid for basic/advanced pairs under one condition. Use a single query field with a schema-neutral placeholder and a wand prompt that covers each search operation --- apps/sim/blocks/blocks/square.ts | 55 +++++++------------------------- 1 file changed, 12 insertions(+), 43 deletions(-) diff --git a/apps/sim/blocks/blocks/square.ts b/apps/sim/blocks/blocks/square.ts index 157c276fcde..5fa282c4bdb 100644 --- a/apps/sim/blocks/blocks/square.ts +++ b/apps/sim/blocks/blocks/square.ts @@ -309,54 +309,24 @@ export const SquareBlock: BlockConfig = { mode: 'advanced', }, - // Search query — one field per search operation so the placeholder and wand - // prompt match each endpoint's distinct query schema. All map to the same - // canonical `query` param. + // Search query — shared across the three search operations. The placeholder + // stays schema-neutral (each endpoint expects a different query shape) and + // the examples for each are spelled out in the wand prompt. { - id: 'queryCustomers', + id: 'query', title: 'Query (JSON)', type: 'code', language: 'json', - canonicalParamId: 'query', - placeholder: '{"filter": {"email_address": {"exact": "customer@example.com"}}}', - condition: { field: 'operation', value: 'search_customers' }, - mode: 'advanced', - wandConfig: { - enabled: true, - prompt: - 'Generate a Square SearchCustomers query JSON object with a filter and optional sort. Return ONLY the JSON object.', - generationType: 'json-object', - }, - }, - { - id: 'queryOrders', - title: 'Query (JSON)', - type: 'code', - language: 'json', - canonicalParamId: 'query', - placeholder: '{"filter": {"state_filter": {"states": ["OPEN"]}}}', - condition: { field: 'operation', value: 'search_orders' }, - mode: 'advanced', - wandConfig: { - enabled: true, - prompt: - 'Generate a Square SearchOrders query JSON object with a filter (e.g. state_filter, date_time_filter) and optional sort. Return ONLY the JSON object.', - generationType: 'json-object', + placeholder: 'Square search query JSON for the selected operation', + condition: { + field: 'operation', + value: ['search_customers', 'search_orders', 'search_catalog_objects'], }, - }, - { - id: 'queryCatalog', - title: 'Query (JSON)', - type: 'code', - language: 'json', - canonicalParamId: 'query', - placeholder: '{"text_query": {"keywords": ["coffee"]}}', - condition: { field: 'operation', value: 'search_catalog_objects' }, mode: 'advanced', wandConfig: { enabled: true, prompt: - 'Generate a Square SearchCatalogObjects query JSON object (e.g. text_query, prefix_query, exact_query). Return ONLY the JSON object.', + 'Generate a Square search query JSON object for the selected operation. For Search Customers use a filter like {"filter":{"email_address":{"exact":"a@b.com"}}}; for Search Orders use {"filter":{"state_filter":{"states":["OPEN"]}}}; for Search Catalog Objects use {"text_query":{"keywords":["coffee"]}}. Return ONLY the JSON object.', generationType: 'json-object', }, }, @@ -707,8 +677,6 @@ export const SquareBlock: BlockConfig = { params: (params) => { const { operation, - uploadFile, - fileRef, address, query, order, @@ -728,8 +696,9 @@ export const SquareBlock: BlockConfig = { ...rest } = params - // Normalize the catalog image file from basic (uploadFile) or advanced (fileRef) - const normalizedFile = normalizeFileInput(uploadFile || fileRef, { single: true }) + // The basic/advanced image inputs are collapsed into the canonical `file` + // param before this runs, so normalize from params.file. + const normalizedFile = normalizeFileInput(params.file, { single: true }) // Parse a JSON-typed input, naming the field in any error so the user // knows exactly which input to fix. From 4c7ea07b587f66f3aefb25a5c3ecd4aca6ae2729 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 00:37:32 -0700 Subject: [PATCH 4/7] chore(square): trigger fresh review From 59179bae6eebec1f85079ae685b75d77b7877c2f Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 01:03:23 -0700 Subject: [PATCH 5/7] fix(square): single-location invoice search and guard numeric coercion - SearchInvoices: Square's invoice filter accepts only one location, so take a single locationId (string) instead of an array and wrap it as query.filter.location_ids: [locationId] - Block: fail locally with a clear " must be a valid number" error when amount/limit/version/orderVersion are non-numeric instead of forwarding NaN --- .../content/docs/en/integrations/square.mdx | 2 +- apps/sim/blocks/blocks/square.ts | 40 ++++++++++++++----- apps/sim/tools/square/search_invoices.ts | 8 ++-- apps/sim/tools/square/types.ts | 2 +- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/apps/docs/content/docs/en/integrations/square.mdx b/apps/docs/content/docs/en/integrations/square.mdx index 73c60e96f5f..d741dbdb24d 100644 --- a/apps/docs/content/docs/en/integrations/square.mdx +++ b/apps/docs/content/docs/en/integrations/square.mdx @@ -1129,7 +1129,7 @@ Search invoices across one or more locations | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `apiKey` | string | Yes | Square access token \(personal access token\) | -| `locationIds` | array | Yes | Array of location IDs to search within | +| `locationId` | string | Yes | ID of the location to search within \(Square allows one location per search\) | | `limit` | number | No | Maximum number of results to return per page | | `cursor` | string | No | Pagination cursor from a previous response | diff --git a/apps/sim/blocks/blocks/square.ts b/apps/sim/blocks/blocks/square.ts index 5fa282c4bdb..54ad0c87916 100644 --- a/apps/sim/blocks/blocks/square.ts +++ b/apps/sim/blocks/blocks/square.ts @@ -381,9 +381,9 @@ export const SquareBlock: BlockConfig = { placeholder: '["L123", "L456"]', condition: { field: 'operation', - value: ['search_orders', 'search_invoices', 'batch_retrieve_inventory_counts'], + value: ['search_orders', 'batch_retrieve_inventory_counts'], }, - required: { field: 'operation', value: ['search_orders', 'search_invoices'] }, + required: { field: 'operation', value: 'search_orders' }, }, // Invoices @@ -563,9 +563,16 @@ export const SquareBlock: BlockConfig = { placeholder: 'Square location ID', condition: { field: 'operation', - value: ['create_payment', 'list_payments', 'list_invoices', 'list_refunds', 'get_location'], + value: [ + 'create_payment', + 'list_payments', + 'list_invoices', + 'search_invoices', + 'list_refunds', + 'get_location', + ], }, - required: { field: 'operation', value: ['list_invoices', 'get_location'] }, + required: { field: 'operation', value: ['list_invoices', 'search_invoices', 'get_location'] }, }, { id: 'limit', @@ -725,6 +732,22 @@ export const SquareBlock: BlockConfig = { const parsedCatalogObjectIds = parseJsonField(catalogObjectIds, 'catalogObjectIds') const parsedStates = parseJsonField(states, 'states') + // Coerce a numeric input, failing locally with a clear message rather than + // forwarding NaN to Square when the value is non-numeric. + const coerceNumber = (value: unknown, field: string): number | undefined => { + if (value === undefined || value === null || value === '') return undefined + const num = Number(value) + if (!Number.isFinite(num)) { + throw new Error(`"${field}" must be a valid number`) + } + return num + } + + const coercedAmount = coerceNumber(amount, 'amount') + const coercedLimit = coerceNumber(limit, 'limit') + const coercedVersion = coerceNumber(version, 'version') + const coercedOrderVersion = coerceNumber(orderVersion, 'orderVersion') + return { ...rest, ...(normalizedFile && { file: normalizedFile }), @@ -738,11 +761,10 @@ export const SquareBlock: BlockConfig = { ...(parsedPaymentIds !== undefined && { paymentIds: parsedPaymentIds }), ...(parsedCatalogObjectIds !== undefined && { catalogObjectIds: parsedCatalogObjectIds }), ...(parsedStates !== undefined && { states: parsedStates }), - ...(amount !== undefined && amount !== '' && { amount: Number(amount) }), - ...(limit !== undefined && limit !== '' && { limit: Number(limit) }), - ...(version !== undefined && version !== '' && { version: Number(version) }), - ...(orderVersion !== undefined && - orderVersion !== '' && { orderVersion: Number(orderVersion) }), + ...(coercedAmount !== undefined && { amount: coercedAmount }), + ...(coercedLimit !== undefined && { limit: coercedLimit }), + ...(coercedVersion !== undefined && { version: coercedVersion }), + ...(coercedOrderVersion !== undefined && { orderVersion: coercedOrderVersion }), ...(autocomplete !== undefined && { autocomplete: autocomplete === 'true' }), ...(includeRelatedObjects !== undefined && { includeRelatedObjects: includeRelatedObjects === 'true', diff --git a/apps/sim/tools/square/search_invoices.ts b/apps/sim/tools/square/search_invoices.ts index 509d1d20089..90fecaae2b0 100644 --- a/apps/sim/tools/square/search_invoices.ts +++ b/apps/sim/tools/square/search_invoices.ts @@ -22,11 +22,11 @@ export const squareSearchInvoicesTool: ToolConfig { const body: Record = { query: { - filter: { location_ids: params.locationIds }, + filter: { location_ids: [params.locationId] }, }, } if (params.limit !== undefined) body.limit = params.limit diff --git a/apps/sim/tools/square/types.ts b/apps/sim/tools/square/types.ts index 3e4cde67a26..ff230d76766 100644 --- a/apps/sim/tools/square/types.ts +++ b/apps/sim/tools/square/types.ts @@ -892,7 +892,7 @@ export interface PayOrderParams { export interface SearchInvoicesParams { apiKey: string - locationIds: string[] + locationId: string limit?: number cursor?: string } From 580e9819305cefccd7fe5b5016ccb14561ff7c44 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 01:09:30 -0700 Subject: [PATCH 6/7] fix(square): accept real booleans for autocomplete/includeRelatedObjects Coerce these from both the dropdown's string values and actual booleans (which can arrive via connected blocks or templated inputs), so true is not silently flipped to false. --- apps/sim/blocks/blocks/square.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/sim/blocks/blocks/square.ts b/apps/sim/blocks/blocks/square.ts index 54ad0c87916..40fb59e9037 100644 --- a/apps/sim/blocks/blocks/square.ts +++ b/apps/sim/blocks/blocks/square.ts @@ -743,6 +743,10 @@ export const SquareBlock: BlockConfig = { return num } + // Accept both the dropdown's string values and real booleans (which can + // arrive via connected blocks or templated inputs). + const coerceBoolean = (value: unknown): boolean => value === true || value === 'true' + const coercedAmount = coerceNumber(amount, 'amount') const coercedLimit = coerceNumber(limit, 'limit') const coercedVersion = coerceNumber(version, 'version') @@ -765,9 +769,9 @@ export const SquareBlock: BlockConfig = { ...(coercedLimit !== undefined && { limit: coercedLimit }), ...(coercedVersion !== undefined && { version: coercedVersion }), ...(coercedOrderVersion !== undefined && { orderVersion: coercedOrderVersion }), - ...(autocomplete !== undefined && { autocomplete: autocomplete === 'true' }), + ...(autocomplete !== undefined && { autocomplete: coerceBoolean(autocomplete) }), ...(includeRelatedObjects !== undefined && { - includeRelatedObjects: includeRelatedObjects === 'true', + includeRelatedObjects: coerceBoolean(includeRelatedObjects), }), } }, From 6b161a70935f46c1bfb98abc97a684ad70923823 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 01:15:28 -0700 Subject: [PATCH 7/7] fix(square): validate parsed JSON field shapes (array vs object) parseJsonField now enforces the expected shape so a valid-but-wrong-type value (e.g. a JSON string where an array is expected for locationIds/objectTypes/ paymentIds/catalogObjectIds/states, or a non-object for order/invoice/etc.) fails locally with a clear message instead of a confusing Square API error. --- apps/sim/blocks/blocks/square.ts | 56 +++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/apps/sim/blocks/blocks/square.ts b/apps/sim/blocks/blocks/square.ts index 40fb59e9037..17d4f7c295e 100644 --- a/apps/sim/blocks/blocks/square.ts +++ b/apps/sim/blocks/blocks/square.ts @@ -708,29 +708,47 @@ export const SquareBlock: BlockConfig = { const normalizedFile = normalizeFileInput(params.file, { single: true }) // Parse a JSON-typed input, naming the field in any error so the user - // knows exactly which input to fix. - const parseJsonField = (value: unknown, field: string): unknown => { + // knows exactly which input to fix, and validating the parsed shape so a + // valid-but-wrong-type value (e.g. a string where an array is expected) + // fails locally instead of as a confusing Square API error. + const parseJsonField = ( + value: unknown, + field: string, + expected: 'object' | 'array' + ): unknown => { if (value === undefined || value === null || value === '') return undefined - if (typeof value !== 'string') return value - try { - return JSON.parse(value) - } catch (error) { - throw new Error( - `Invalid JSON in "${field}": ${error instanceof Error ? error.message : 'unknown error'}` - ) + let parsed: unknown = value + if (typeof value === 'string') { + try { + parsed = JSON.parse(value) + } catch (error) { + throw new Error( + `Invalid JSON in "${field}": ${error instanceof Error ? error.message : 'unknown error'}` + ) + } } + if (expected === 'array' && !Array.isArray(parsed)) { + throw new Error(`"${field}" must be a JSON array`) + } + if ( + expected === 'object' && + (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) + ) { + throw new Error(`"${field}" must be a JSON object`) + } + return parsed } - const parsedAddress = parseJsonField(address, 'address') - const parsedQuery = parseJsonField(query, 'query') - const parsedOrder = parseJsonField(order, 'order') - const parsedInvoice = parseJsonField(invoice, 'invoice') - const parsedObject = parseJsonField(object, 'object') - const parsedLocationIds = parseJsonField(locationIds, 'locationIds') - const parsedObjectTypes = parseJsonField(objectTypes, 'objectTypes') - const parsedPaymentIds = parseJsonField(paymentIds, 'paymentIds') - const parsedCatalogObjectIds = parseJsonField(catalogObjectIds, 'catalogObjectIds') - const parsedStates = parseJsonField(states, 'states') + const parsedAddress = parseJsonField(address, 'address', 'object') + const parsedQuery = parseJsonField(query, 'query', 'object') + const parsedOrder = parseJsonField(order, 'order', 'object') + const parsedInvoice = parseJsonField(invoice, 'invoice', 'object') + const parsedObject = parseJsonField(object, 'object', 'object') + const parsedLocationIds = parseJsonField(locationIds, 'locationIds', 'array') + const parsedObjectTypes = parseJsonField(objectTypes, 'objectTypes', 'array') + const parsedPaymentIds = parseJsonField(paymentIds, 'paymentIds', 'array') + const parsedCatalogObjectIds = parseJsonField(catalogObjectIds, 'catalogObjectIds', 'array') + const parsedStates = parseJsonField(states, 'states', 'array') // Coerce a numeric input, failing locally with a clear message rather than // forwarding NaN to Square when the value is non-numeric.