> ## Documentation Index
> Fetch the complete documentation index at: https://docs.craveup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Square commerce setup

> Connect Square as the operational commerce authority for menu, checkout, orders, refunds, loyalty, and gift-card tenders.

When an eligible Square connection is active for a location, Square is the
source of truth for operational catalog data, order calculation, customer
payments, refunds, loyalty, gift-card tenders, and the Square fulfillment
lifecycle. Checkout remains embedded in Crave through Square Web Payments.
Stripe is selected only for locations without an active Square connection; an
in-progress cart never switches processors silently.

## Activation flow

<Steps>
  <Step title="Connect Square via OAuth">
    Authorize the requested merchant, customer, catalog, order, payment, refund, card, gift-card,
    inventory, location, and loyalty scopes.
  </Step>

  <Step title="Map one Square location">
    Bind the Crave location to the exact Square location after currency, timezone, and capability
    checks.
  </Step>

  <Step title="Import, review, and activate Menu Sync">
    Resolve catalog exceptions and activate a fresh, reviewed snapshot. Square owns price, tax,
    discounts, availability, and schedule after activation.
  </Step>

  <Step title="Verify commerce readiness">
    Confirm checkout, webhook, and reconciliation health in the Dashboard before accepting traffic.
    Delivery additionally requires explicit Square Delivery certification and DoorDash Drive
    credentials.
  </Step>
</Steps>

## Authority rules

* A connected and mapped Square location uses Square Payments. Stripe is not a
  fallback after Square has started a checkout.
* Crave never receives raw card or gift-card data. Square Web Payments returns
  a token that the server uses with the mapped seller and location.
* Square calculates the order using mapped catalog variations, automatic taxes,
  automatic discounts, service charges, and an optional order-linked Loyalty
  reward. A customer-entered Crave coupon is rejected for Square commerce.
* Staff tip is recorded on the final Square Payment. DoorDash courier tip and
  the authoritative Drive fee plus tax are Square Order service charges.
* Gift cards can partially authorize first; one final card, wallet, or stored
  card pays the remaining balance. Saved cards require authenticated customer
  ownership, buyer verification, and explicit consent. When a customer selects
  a saved card, the storefront passes its opaque Card ID back to Square Web
  Payments `Card.tokenize` with the current amount, currency, buyer contact,
  `customerInitiated=true`, and `sellerKeyedIn=false`. Only the resulting
  authenticated one-time payment token is used as the Square payment source;
  the deprecated separate `verificationToken` field is not part of the Crave
  payment contract. The selected Card ID remains server-side ownership
  evidence. The storefront sends the current versioned
  `cardSaveConsent` object only after the customer selects “Save this card
  securely with Square for future orders.” Before calling Square `CreateCard`,
  Crave writes immutable tenant-, customer-, connection-, and checkout-scoped
  consent evidence. Removing a saved card disables it in Square and records a
  separate revocation event. Crave stores a separate Square customer identity
  for each connected Square seller account, so cards and Loyalty never cross
  merchant boundaries when one Crave organization operates multiple Square
  accounts.
* Authenticated customers can buy a new digital Square gift card in Crave. A
  non-gift-card Square payment must complete before activation; the card is
  linked to the same Square customer and its full number is returned once over
  a private, no-store response. Crave projections, logs, and webhook storage
  retain only safe IDs or redacted values.
* Full and partial refunds return to gift-card tenders first, then the remaining
  card or wallet tenders. Mixed outcomes are surfaced as action required.
* A refund of the payment that purchased a gift card triggers an idempotent
  Square `ADJUST_DECREMENT` activity with reason `PURCHASE_WAS_REFUNDED`, because
  refunding that funding payment does not reverse the loaded gift-card balance.
* Square Loyalty replaces LIP for Square-authoritative locations. Enrollment,
  reward preview, issue, redemption, point accrual, and webhook projection use
  the Square customer and Loyalty account.
* Checkout reads the member quote from `GET .../loyalty/quote`. A first-time
  member joins through the separate, explicitly consented
  `POST .../loyalty/enrollment` mutation before earning can begin; applying a
  reward never enrolls a customer as a side effect. Enrollment, reward apply,
  and reward removal require the current cart revision and an idempotency key,
  and each refreshes the Square payment session before payment can continue.
* Enrollment requires a phone that the active Crave customer has verified by
  OTP. Checkout can add that factor to the current customer through
  `POST /customer/phone-verification` and confirm it through
  `POST /customer/phone-verification/confirmation`; an E.164-shaped profile
  value alone is not accepted as proof. Crave's one-time verification consent
  does not accept Square marketing text terms.
* Customer loyalty history is location-scoped at
  `GET /customer/locations/{locationId}/loyalty/ledger`. A Square-authoritative
  location reads the current balance with `RetrieveLoyaltyAccount` and the
  reverse-chronological activity ledger with `SearchLoyaltyEvents` (up to 30
  entries per page). It never falls back to LIP when Square is connected. The
  retained location binding keeps that exclusion in force if Square credentials
  or runtime health degrade, so Crave cannot mutate a second loyalty ledger
  through quote, cart, completion, cancellation, refund, or durable retry
  hooks. A queued LIP mutation rechecks the task location before delivery and
  terminates without a provider call after Square takes authority. Legacy tasks
  without location authority fail closed as well.
* When an administrator approves a customer loyalty claim, Crave resolves the
  claim order's location before choosing the provider. A Square-authoritative
  order writes the approved correction through Square `AdjustLoyaltyPoints`
  with a stable provider idempotency key and retains the returned Square event
  ID. Provider errors leave the claim retryable; Crave never posts that
  adjustment to LIP. Orders at locations without Square authority continue to
  use the configured LIP program.
* Completed Square orders accrue Loyalty points with an order-scoped provider
  idempotency key. A failed or ambiguous accrual is retained as a durable
  `LOYALTY_EFFECT` operation; the worker re-proves the completed Square tenders,
  current tenant and location binding, and returned Loyalty events before it
  marks the cart projection complete.
* Vendor confirmation, ready-for-pickup, and completion actions update the
  exact Square fulfillment before Crave commits the matching local state. Each
  update uses the current Square order version, fulfillment UID, and a stable
  idempotency key. Square-originated fulfillment webhooks apply locally without
  echoing the same transition back to Square.

## Delivery with DoorDash Drive

Delivery is fail-closed until the location has fresh capability evidence whose
source is `square_live_pos_delivery_certification`, a selected
`DOORDASH_DRIVE` provider, and valid Drive credentials.

Crave requests a five-minute Drive quote, fingerprints its address and cart
inputs, adds `fee + tax` and courier tip to the Square Order, pays that exact
order, then accepts the same Drive quote. Definite dispatch rejection triggers
idempotent Square refund compensation. An ambiguous timeout is reconciled using
the same external delivery ID and is never auto-refunded while a courier job
might exist. DoorDash webhooks update Crave tracking and the Square delivery
fulfillment.

Active deliveries are also retrieved every 60 seconds when their last
reconciliation is more than two minutes old, so a missing webhook does not
strand tracking state. Order cancellation reaches a conclusive DoorDash cancel
state before Square refund processing begins.

## Apple Pay domains

Apple Pay requires the storefront's exact HTTPS domain to be registered for
this Square application. Crave proxies Square's current
`apple-developer-merchantid-domain-association` file at
`/.well-known/apple-developer-merchantid-domain-association` without an
extension or long-lived cache. Then add the host under **Apple Pay** in Square
Developer Console, using Sandbox mode for a sandbox storefront and Production
mode for production. Apple Pay cannot be verified on localhost.

## Webhooks

Create the Square subscription against:

```text theme={null}
https://<sandbox-api-host>/api/v1/webhooks/square
```

Subscribe to the exact events handled by this release:

```text theme={null}
catalog.version.updated
inventory.count.updated
location.created
location.updated
order.created
order.updated
order.fulfillment.updated
payment.created
payment.updated
refund.created
refund.updated
customer.created
customer.updated
customer.deleted
card.created
card.updated
card.disabled
card.forgotten
card.automatically_updated
loyalty.account.created
loyalty.account.updated
loyalty.account.deleted
loyalty.event.created
loyalty.program.created
loyalty.program.updated
loyalty.promotion.created
loyalty.promotion.updated
gift_card.created
gift_card.updated
gift_card.customer_linked
gift_card.customer_unlinked
gift_card.activity.created
gift_card.activity.updated
oauth.authorization.revoked
```

Set `SQUARE_WEBHOOK_SIGNATURE_KEY` only in the sandbox secret manager. Never
paste it into tickets, chat, source control, or browser configuration. Crave
verifies Square's signature over the untouched body and exact notification URL,
then acknowledges only after durable inbox storage.

For DoorDash Drive, register:

```text theme={null}
https://<sandbox-api-host>/api/v1/webhooks/doordash
```

Configure the same Basic or OAuth `Authorization` value in DoorDash and the
`DOORDASH_WEBHOOK_AUTHORIZATION` sandbox secret. Crave compares the exact value
in constant time, durably stores the event, serializes delivery projections,
and retries failures.

## Health and recovery

The Square integration page shows authorization and mapping status, capability
readiness, last reconciliation, last webhook receipt, and pending or failed
events. Use **Reconcile** to refresh locations, catalog, inventory, orders,
payments, refunds, customers, cards, Loyalty programs, promotions, accounts,
events and rewards, plus gift cards and their location activity. Gift-card
account numbers are redacted before reconciliation evidence is stored. Use
**Retry events** after repairing a dependency. A webhook HTTP success means the
event was stored; projection occurs asynchronously and remains observable.

The runtime also enqueues one tenant-scoped full completeness sweep for every
mapped Square location in each UTC day. The durable operation pins the exact
organization, connection, and binding, runs the same canonical path as the
operator action, and records the successful system reconciliation in the
health timeline. Provider or network failures use bounded exponential retry;
an expired read-only lease is safe to replay, while changed binding evidence
fails closed for operator review. Faster catalog, webhook, payment/refund,
checkout-abandonment, Loyalty, and DoorDash workers continue to repair their
own nonterminal domains between full sweeps.

## Admin endpoints

| Method   | Path                                                | Purpose                       |
| -------- | --------------------------------------------------- | ----------------------------- |
| `POST`   | `/locations/:id/integrations/square/oauth`          | Start OAuth                   |
| `GET`    | `/locations/:id/integrations/square`                | Status, health, capabilities  |
| `GET`    | `/locations/:id/integrations/square/locations`      | List Square locations         |
| `POST`   | `/locations/:id/integrations/square/locations`      | Bind the Square location      |
| `POST`   | `/locations/:id/integrations/square/catalog/import` | Import the catalog            |
| `POST`   | `/locations/:id/integrations/square/reconcile`      | Run full reconciliation       |
| `POST`   | `/locations/:id/integrations/square/events/retry`   | Retry failed webhook events   |
| `DELETE` | `/locations/:id/integrations/square`                | Disconnect after deactivation |

Disconnecting preserves canonical catalog and historical evidence. Active or
degraded commerce modules must be deactivated or rolled back first.

<Snippet file="need-help.mdx" />
