2026-09-16. It covers payments with the sandbox test nonces, delayed capture, completion, and cancellation; refunds, including partial ones; orders whose totals are computed on the server from line items, taxes, discounts, and service charges; customers; the catalog, with temporary #ids mapped in id_mappings; locations and merchants. Writes take idempotency keys, lists page with cursors, and errors use Square’s errors envelope. It also covers OAuth (authorization code and PKCE flows, refresh, revoke, token status) with scopes checked per endpoint, and webhook subscriptions whose events are signed in x-square-hmacsha256-signature. The tests drive it with the official square SDK (46.0.0) and verify webhook signatures with its WebhooksHelper.verifySignature.
At a glance
Start
--service. When it is the only enabled service, it listens on http://localhost:4000. Without config, the seller is Default Test Account with one main location and a default application (sandbox-sq0idb-baseline).
Point the SDK at the emulator with baseUrl:
URL mapping
Auth
Requests sendAuthorization: Bearer <token>.
- A token the CLI accepts (for example
test_token_admin) acts as the first application’s personal access token, with every scope. apps[].personal_access_tokenacts as that application, with every scope.tokens[]seeds extra tokens. Withscopesit behaves like an OAuth access token limited to those scopes; without them it is a personal token.- OAuth access tokens carry the scopes the seller approved.
UNAUTHORIZED. Revoked and expired tokens answer ACCESS_TOKEN_REVOKED and ACCESS_TOKEN_EXPIRED. A token without an endpoint’s scope answers 403 INSUFFICIENT_SCOPES and names the missing scopes.
OAuth
GET /oauth2/authorize?client_id=...&scope=PAYMENTS_WRITE+ORDERS_READ&state=...— Authorize: shows a consent page with the requested permissions. Approving redirects to the application’s redirect URL withcode,response_type=code, andstate; declining sendserror=access_denied.POST /oauth2/token— Obtain token: withgrant_type=authorization_code,client_id,client_secret, andcode. Public clients sendcode_verifierinstead of the secret (PKCE,S256orplain). Access tokens last 30 days, or 24 hours withshort_lived: true.- The same call with
grant_type=refresh_tokenrefreshes a token. In the code flow the refresh token stays the same; in the PKCE flow it is single use, rotated on every refresh, and expires after 90 days.scopesnarrows a refresh. POST /oauth2/revoke— Revoke token: withAuthorization: Client <secret>and anaccess_tokenormerchant_id, it revokes the grant (revoke_only_access_tokenkeeps the refresh token) and sendsoauth.authorization.revoked.POST /oauth2/token/status— Retrieve token status: reports a token’s scopes, expiry, client, and merchant.
Requests
Square-Version
TheSquare-Version header is optional. Without it, requests are answered at 2026-09-16. A value that is not YYYY-MM-DD answers 400 INVALID_SQUARE_VERSION_FORMAT. Webhook subscriptions keep the version they were created with.
Idempotency
Writes takeidempotency_key in the body. The same key with the same body returns the first answer, including a decline; with a different body it answers 400 IDEMPOTENCY_KEY_REUSED. Keys are scoped to the application and the endpoint.
Pagination
List and search endpoints returncursor when there is more. A cursor is tied to the filters it came from; any other value answers INVALID_CURSOR.
Payments
POST /v2/payments— Create payment:source_id,idempotency_key,amount_money, and optionallytip_money,app_fee_money,autocomplete,delay_duration,delay_action,order_id,customer_id,location_id,reference_id,note, andbuyer_email_addressGET /v2/payments— List payments: filters bybegin_time,end_time,sort_order,location_id,total,last_4, andcard_brand, and pages withcursorandlimitGET /v2/payments/:id— Get paymentPUT /v2/payments/:id— Update payment: amounts and tip of anAPPROVEDpayment, withversion_tokenPOST /v2/payments/:id/complete— Complete paymentPOST /v2/payments/:id/cancel— Cancel paymentPOST /v2/payments/cancel— Cancel payment by idempotency key
autocomplete: false a card payment stays APPROVED until it is completed or canceled. After delay_duration (default PT168H) the delay_action (CANCEL by default, or COMPLETE) is applied. Completing or canceling a payment that is not APPROVED answers DELAYED_TRANSACTION_CAPTURED, DELAYED_TRANSACTION_CANCELED, or DELAYED_TRANSACTION_FAILED.
A payment against an order must match the order’s amount due (PAYMENT_AMOUNT_MISMATCH) and location (LOCATION_MISMATCH). When the order is fully paid it gets a tender and closes, unless it has fulfillments.
Test values
A declined payment is stored as
FAILED and answered with 400 PAYMENT_METHOD_ERROR, the decline code, and the payment. An unknown nonce answers 404 NOT_FOUND. A card ending in 2222 is rated MODERATE risk and 3333 HIGH.
Refunds
POST /v2/refunds— Refund payment: all or part of a completed paymentGET /v2/refunds— List payment refundsGET /v2/refunds/:id— Get payment refund
REFUND_AMOUNT_INVALID, an APPROVED payment REFUND_ERROR_PAYMENT_NEEDS_COMPLETION, and a canceled or failed payment PAYMENT_NOT_REFUNDABLE. Card refunds start PENDING and complete after refund_delay_ms (default one second); cash and external refunds complete at once. The payment’s refunded_money and refund_ids update straight away.
Orders
POST /v2/orders— Create order: line items (catalog variations or ad hoc), taxes (ADDITIVEorINCLUSIVE), discounts (FIXED_PERCENTAGE,FIXED_AMOUNT, at order or line item scope), service charges, and fulfillments. Every total is computed on the serverPOST /v2/orders/calculate— Calculate order: prices an order without saving itPOST /v2/orders/clone— Clone order: copies one into a newDRAFTGET /v2/orders/:id— Retrieve orderPOST /v2/orders/batch-retrieve— Batch retrieve ordersPUT /v2/orders/:id— Update order: with the currentversion(VERSION_MISMATCHotherwise): a sparse update that merges lists byuidand honorsfields_to_clearPOST /v2/orders/search— Search orders:location_ids,state_filter,date_time_filter,customer_filter,source_filter,fulfillment_filter, andsort(the sort field must match the date filter field),return_entries,cursor, andlimitPOST /v2/orders/:id/pay— Pay order:payment_idsthat cover the amount due
Customers
GET /v2/customers— List customersPOST /v2/customers— Create customerDELETE /v2/customers/:id— Delete customer: the same path takesGETandPUT, all withversionchecksPOST /v2/customers/bulk-create— Bulk create customers: alsobulk-retrieve,bulk-update, andbulk-deletePOST /v2/customers/search— Search customers:email_address,phone_number,reference_id,created_at,updated_at, andcreation_sourcefilters and a sort
Catalog
POST /v2/catalog/object— Upsert catalog objectPOST /v2/catalog/batch-upsert— Batch upsert catalog objectsGET /v2/catalog/list— List catalog: filtered bytypesGET /v2/catalog/object/:id— Retrieve catalog object:include_related_objectsPOST /v2/catalog/batch-retrieve— Batch retrieve catalog objectsDELETE /v2/catalog/object/:id— Delete catalog object: deleting an item deletes its variationsPOST /v2/catalog/batch-delete— Batch delete catalog objects: deleting an item deletes its variationsPOST /v2/catalog/search— Search catalog objects:exact_query,set_query,prefix_query,range_query,text_query,items_for_tax_query, andsorted_attribute_queryPOST /v2/catalog/search-catalog-items— Search catalog itemsPOST /v2/catalog/update-item-taxes— Update item taxesGET /v2/catalog/info— Catalog info
#latte, which may refer to each other; the answer maps them in id_mappings. Updating an object needs its current version.
Items, variations, categories, taxes, discounts, modifier lists, and modifiers are stored.
Locations and merchants
POST /v2/locations— Create location:GETon the same path lists themPUT /v2/locations/:id— Update location:GETon the same path retrieves oneGET /v2/merchants— List merchantsGET /v2/merchants/:id— Retrieve merchant:meworks
main stands for the main location, the first one in config. The merchants endpoints describe the seller.
Webhooks
GET /v2/webhooks/event-types— List webhook event typesPOST /v2/webhooks/subscriptions— Create webhook subscription:GETon the same path lists themDELETE /v2/webhooks/subscriptions/:id— Delete webhook subscription: the same path takesGETandPUTPOST /v2/webhooks/subscriptions/:id/signature-key— Update webhook signature key: rotates the keyPOST /v2/webhooks/subscriptions/:id/test— Test webhook subscription: sends a test event and returns the receiver’s answer
payment.created, payment.updated, refund.created, refund.updated, order.created, order.updated, customer.created, customer.updated, customer.deleted, catalog.version.updated, location.created, location.updated, and oauth.authorization.revoked. Each is posted as { merchant_id, type, event_id, created_at, data: { type, id, object } } with x-square-hmacsha256-signature (base64 HMAC-SHA256 of the notification URL followed by the raw body, keyed with the signature key), so WebhooksHelper.verifySignature accepts it:
square-retry-number and square-retry-reason.
Seed config
name: the first location is the main one
catalog entries use Square’s upsert shape, so temporary ids may refer to each other. A webhook without event_types hears every event Baseline sends; without signature_key one is generated.
Inspector
GET /_inspector shows payments with their refunds, orders with their totals, customers, catalog objects, locations, and applications with their tokens and webhook subscriptions. Each payment’s receipt_url opens a receipt page at /_square/receipts/:id.
Limits
Terminal, invoices, subscriptions, gift cards, loyalty, bookings, team, labor, inventory counts, disputes, payouts, cards on file (/v2/cards), and the v1 API. Other /v2 paths answer 404 NOT_FOUND.
Conformance
See CONFORMANCE.md for every provider.