SANDBOX — test deployment of the website. Nothing here is real.

Developers / Guides / Records

Customers, products and tax rates

The records every invoice, schedule and saved card hangs off. Everything here is per merchant, addressed by that merchant's X-Api-Key-scoped {ref} (its externalReference).

Customers

Create a customer, then use the returned customerId everywhere else. You can also give a customer your own account number — your system's number for them — and find them again by it. It is unique per merchant (a duplicate returns 409), it is sent on to any accounting system the merchant has connected, and it is never required.

EndpointPurpose
POST /api/merchant-accounts/{ref}/customersCreate a customer (name, email, phone, website, billing address, optional accountNumber, optional smsConsent).
GET .../customersList the merchant's customers.
GET .../customers?accountNumber=A-1001Find the customer with that account number (an empty list if there is none).
GET .../customers/{customerId}Get one customer.
GET .../customers/{customerId}/sms-consentWhether the customer has agreed to be texted, at which number, and how it was recorded.
PUT .../customers/{customerId}/sms-consentRecord or withdraw the customer's consent to receive texts ({ "consent": true, "phone": "(555) 234-5678" }).

Saved payment methods hang off a customer — see Saved payment methods.

PayMidWare can text a merchant's customers a pay link, a receipt, a failed-payment notice or a reminder before a scheduled payment. It only does so for a customer who has agreed to be texted, at the exact US mobile number they agreed to, and only when the merchant has turned that kind of text on in the Portal (everything is off by default). Texting is a regulated activity, so please read the rules before you record consent.

  • Record only consent the customer actually gave — a clear opt-in on your own form or screen. By sending "consent": true you confirm that the customer gave it. Pre-ticked boxes, or consent given for something else, do not count.
  • Consent is for one number. If the customer's phone number changes, consent has to be recorded again. Omit phone to use the number already stored on the customer; send it to record consent for another number.
  • You can set it when you create the customer ("smsConsent": true with a valid phone, else 400) or later with PUT .../sms-consent. "consent": false withdraws it.
  • STOP always wins. A customer who replies STOP to any text is blocked for that number until they reply START, and their consent is withdrawn. Replying START does not give consent back — the customer has to agree again.
  • Numbers outside the US, and numbers that are not a valid mobile format, are refused (400). Texts are not sent between 9pm and 8am in the merchant's time zone; they are held until morning.
  • The customer can also agree on the pay page after a successful payment, and a merchant's staff can record it on the customer's page in the Portal.
PUT /api/merchant-accounts/{ref}/customers/{customerId}/sms-consent
{ "consent": true, "phone": "(555) 234-5678" }

200 { "consent": true, "phone": "+15552345678", "source": "Api", "recordedAtUtc": "2026-10-08T14:03:11Z" }

Products

A catalog of what the merchant sells. A product has a name, optional SKU (unique per merchant), description, unit price, a kind (Service, NonInventory or Inventory) and a taxable flag. PayMidWare never tracks stock — the kind only decides which kind of item is created or linked in QuickBooks. Put a product on an invoice or scheduled-payment line with productId; the line still carries its own description, price and taxable flag, so editing a product later never rewrites an invoice that already exists.

EndpointPurpose
GET .../productsList products.
GET .../products/{productId}Get one, including whether it is linked to a QuickBooks item.
POST .../productsCreate a product.
PUT .../products/{productId}Edit a product.
POST .../products/{productId}/deactivateTake it out of use (also /activate). Products are never deleted.
PUT .../products/{productId}/categorySet the product's category with categoryId, or clear it with null.

Product categories

Flat groups such as Drinks or Food. A product is in one category at a time (categoryId on the product; send it when creating or editing, leave it out on an edit to keep the current one). The register shows the active categories as colored buttons above the products, and GET .../products accepts a categoryId filter. A name is at most 100 characters and cannot contain a colon; a bad name returns 400 and a duplicate returns 409. Color is #RRGGBB. Categories are never deleted, only deactivated. With QuickBooks Online they sync as QuickBooks categories when the company has item categories turned on.

EndpointPurpose
GET .../product-categoriesList categories (includeInactive=true to include switched-off ones).
GET .../product-categories/{categoryId}Get one.
POST .../product-categoriesCreate a category (name, optional color).
PUT .../product-categories/{categoryId}Rename, recolor or reorder (sortOrder).
POST .../product-categories/{categoryId}/deactivateHide it from the register (also /activate).

Tax rates

Named rates such as "NY State 4%" (a percentage from 0 to 100, up to four decimals). One rate can be the merchant's default. Send taxRateId when creating an invoice (or an itemized schedule) and that rate is used; otherwise send a typed taxRatePercent. A rate's percentage is copied onto the invoice when it is created, so changing a rate later does not change existing invoices.

EndpointPurpose
GET .../tax-ratesList rates.
GET .../tax-rates/suggestion?postalCode=QuickBooks automatic sales tax: the combined rate QuickBooks was last seen charging for that ship-to postal code (found, percent, its jurisdictions, lastConfirmedAtUtc, isStale after 30 days). A suggestion only; send it as taxRatePercent on the invoice if you want it.
GET .../tax-rates/observedThe newest observed rate for each postal code, and whether the merchant's QuickBooks Online company has automatic sales tax on.
POST .../tax-ratesCreate a rate.
PUT .../tax-rates/{taxRateId}Edit a rate.
POST .../tax-rates/{taxRateId}/defaultMake it the merchant's default.
POST .../tax-rates/{taxRateId}/deactivateTake it out of use (also /activate).

Tax is worked out per line: only lines with isTaxable: true (the default) are taxed, at the invoice's rate, and the tax is rounded per line. Merchants connected to QuickBooks can also import their QuickBooks tax rates and sync their products from the Portal.

Locations

A merchant's stores or sites. A location has a name, an address, a phone and, optionally, its own tax rate (taxRateId, one of the merchant's named rates). They are the same locations the point-of-sale registers belong to. A register sale uses the rate of the register's location, and an invoice created with a locationId starts on it; a location with no rate of its own (or whose rate is switched off) uses the merchant's default. Locations are never deleted: set isActive to false to switch one off (refused while it has active registers, or when it is the last active location).

EndpointPurpose
GET .../locationsList locations (includeInactive=true to include switched-off ones).
GET .../locations/{locationId}Get one.
POST .../locationsCreate a location (name, optional taxRateId, phone, address fields).
PUT .../locations/{locationId}Replace its name, isActive, tax rate, phone and address (anything left out is cleared).
GET .../locations/settingsWhether the merchant uses locations (locationsEnabled) and its defaultLocationId.
PUT .../locations/settingsReplace both settings. The default must be one of the merchant's active locations.
PUT .../locations/{locationId}/defaultMake this location the default.
DELETE .../locations/defaultClear the default.
PUT .../customers/{customerId}/locationSet (or, with locationId: null, clear) the customer's usual location.

On POST .../invoices, send locationId to raise the invoice for a location. When neither taxRateId nor a non-zero taxRatePercent is sent, the location's own rate is used; an explicit rate or percentage always wins. The location is recorded on the invoice (locationId).

Default location. When the merchant has locations switched on, a new invoice, charge or customer-linked record with no locationId gets the customer's location, else the merchant's default. A locationId you send always wins and must be the merchant's own (otherwise 400). This applies to new records only; changing a default or a customer's location never changes an existing invoice. Charges accept locationId too, and the transaction records it (it is not sent to the gateway); captures, refunds and voids keep the original charge's location. POST .../customers takes an optional locationId.

Location codes. A location can carry a short code (1 to 6 letters or digits, stored in capitals, unique per merchant; send it on POST and PUT .../locations, left out clears it). Merchants can place it in their invoice numbers with {LOC}, for example {LOC}-{YY}-{#####} gives NYC-26-00042. An invoice with no location, or whose location has no code, leaves it out.