# PUT /api/customers/{id}

Update customer

Updates an existing customer's information and payment preferences.

**Operation ID:** `customersUpdate`

## Authorization

Requires: Customers.Customers, Customers.Customers.Update, merchant scope.

Requires API key scope: `customers`

Required permissions:
- `Customers.Customers`
- `Customers.Customers.Update`

## Parameters

| Name | In | Required | Type | Description |
| --- | --- | --- | --- | --- |
| id | path | yes | string(uuid) |  |
| suppressNulls | query | no | boolean | If true, omit properties with null values. |

## Request Body

**Content type:** `application/json`

Schema: [`CustomerUpdateDto`](https://devportal.demo.winkpg.io/docs/api/models/CustomerUpdateDto.md)

Properties:
- `createdFromTemplateId` (string(uuid)): (nullable)
- `name` (string) required: Gets or sets the name of the customer. Must be unique within the owning merchant, compared  case-insensitively. Use `displayName` for a human label that may repeat. (nullable, min length 2, max length 100)
- `displayName` (string): An optional human-readable label for the customer that is deliberately not unique. Supply it  when the recognisable name for two customers is legitimately the same and `name`  carries an external key instead. When present it is what merchants see wherever customers are  listed; when absent those surfaces fall back to `name`. At most 100 characters. (nullable, max length 100)
- `merchantAssignedId` (string): An optional identifier the merchant assigns to the customer as a friendly reference, distinct  from the system Guid `id` and the server-owned legacy number. Surfaces the v1  API's `CustomerId` field. Not an `EditFormField`: it is set through the API rather  than the standard customer form. (nullable, max length 50)
- `merchantId` (string(uuid)) required: Gets or sets the identifier of the merchant that owns this customer.
- `isActive` (boolean): Gets or sets a value indicating whether this customer is active.
- `contactDetail` ([CustomerContactDetail](https://devportal.demo.winkpg.io/docs/api/models/CustomerContactDetail.md)): Gets or sets the customer's contact details (email, phone, address).
  Fields:
  - `primaryContactName` (string): (nullable, max length 100)
  - `emailAddress` (string): The contact's email address. Optional. A value that is not blank must be a valid email address. Conditional: When EmailAddress is not empty. Must be a valid email. (nullable)
  - `phone` (string): The contact's phone number. Optional. A value that is not empty must be a phone number: digits,  with an optional leading `+` and country code, optional parentheses around the area code,  and a space, hyphen or period between groups. Letters, including an extension such as  `x123`, are rejected. (nullable)
  - `fax` (string): The contact's fax number. Optional. Follows the same rule as the phone number. (nullable)
  - `companyUrl` (string): The company's website address. Optional. A value sent without a scheme, such as  `www.example.com`, is stored with `https://` added. A value that starts with  `http://` or `https://` is stored exactly as sent. Any other scheme, and text that is  not a website address, is rejected. (nullable)
  - `addresses` (array<[CustomerAddress](https://devportal.demo.winkpg.io/docs/api/models/CustomerAddress.md)>): The customer's addresses on file. Optional: omit the member, send an empty array, or send  null to record a customer with no address on file. When one or more entries are supplied,  exactly one must be flagged `isDefault`, and every entry must carry `address1`,  `city`, `state` and `zip`. (nullable)
- `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): Gets or sets the collection of tags used to categorize or label this customer. (nullable)
  Fields of each item:
  - `name` (string): (nullable, min length 0, max length 50)
  - `value` (string): (nullable, min length 0, max length 150)
- `storedPaymentMethods` (array<[CustomerStoredPaymentMethod](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethod.md)>): Gets or sets the customer's stored payment methods for recurring or future transactions. (nullable)
  Fields of each item:
  - `id` (string(uuid)): (read only)
  - `paymentMethodType` ([CustomerStoredPaymentMethodType](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethodType.md)): Specifies the type of a stored payment method associated with a customer.
    Values:
    - `Card`
    - `Check`
  - `paymentTokenId` (string(uuid)): (nullable)
  - `cardData` ([CardData](https://devportal.demo.winkpg.io/docs/api/models/CardData.md)): Required: When PaymentMethodType == Card.
  - `checkData` ([CheckData](https://devportal.demo.winkpg.io/docs/api/models/CheckData.md)): Required: When PaymentMethodType == Check.
  - `isDefault` (boolean)
  - `displayName` (string): (nullable, read only)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `customName` (string): Optional user-defined name for this stored payment method (e.g., "Marriott Chase",  "Bank of America Checkcard"). When set, takes priority over the computed display name. (nullable)
  - `initialSchemeTransactionId` (string): The initial (first-in-series) network / scheme transaction id captured from the processor's  authorization response on the cardholder-initiated credential-on-file transaction that stored  this credential. Lets any later transaction (CIT-COF or MIT, any card brand) resolve and echo  the original network transaction id from just the stored token / payment method, without  depending on a StoredCredentialConsent lookup. (nullable)
  - `lastSchemeTransactionId` (string): The most-recent-in-series network / scheme transaction id. At tokenization this equals  `initialSchemeTransactionId`. Card-network rules (Visa 11.1.5, Mastercard 13.1.1)  allow the most recent value in a series to be sent when the original is unavailable, so a later  story can advance this on each subsequent authorization response without losing the first-in-  series anchor. Nullable / non-sensitive as for `initialSchemeTransactionId`. (nullable)
  - `schemeTransactionIdBrand` (string): The card brand at the moment the network transaction id was captured (e.g. "Visa",  "Mastercard", "Discover", "Amex"). Retained because a co-branded card can switch networks  after storage; Mastercard's AltNetTranID handling requires the brand-at-capture to detect the  case where a stored Visa id must be sent in a Mastercard field. Emitting AltNetTranID is out of  scope here: this only preserves the data so the downstream echo work is not precluded.  Nullable / non-sensitive. (nullable)
  - `schemeTransactionIdProcessor` (string): The processor the network transaction id originated from ("tsys" / "fiserv"). The two  processors' response formats differ (TSYS a single 15-char Transaction Identifier; Fiserv  per-brand, whose Visa value can exceed 15 chars including the trailing Validation Code), so the  id is stored opaquely and tagged with its originating processor. Nullable / non-sensitive. (nullable)
  - `publicReference` (string): The externally-emitted, chargeable `PublicReference` of the backing `PaymentToken`  (the opaque `pt_`-prefixed handle) captured when this stored method was minted. Persisted  here so the tokenize-on-payment path can surface it on the transaction response / webhook  without re-reading the token, and so a later charge can round-trip the merchant-facing handle.  Distinct from `paymentTokenId`, which is the internal vault Guid (PAN-correlated,  never emitted). May be `null` on a stored method created before this field existed, until  a one-time platform backfill copies the backing token's handle onto it; the backfill only ever  fills a null and never rewrites an assigned handle. Non-sensitive (an opaque random handle,  not a PAN). (nullable)
  - `origin` ([StoredPaymentMethodOrigin](https://devportal.demo.winkpg.io/docs/api/models/StoredPaymentMethodOrigin.md)): The surface / add-channel this stored payment method was captured through (manual admin,  hosted payment page, virtual terminal, or API). Stamped once at creation and not changed  afterward. (nullable)
    Values:
    - `Unknown`: The add-channel was not recorded. Assigned to methods that predate this field (materialized from a null value) and to any path that did not classify its origin.
    - `ManualAdmin`: Added by an operator through a Customer admin surface that mints the stored method on the customer document directly (the customer edit form's payment-methods dialog, and the create-customer / create-contract-from-transaction dialogs). Note: the contract add-payment dialog submits through the HTTP add endpoint and is therefore recorded as Api, since origin on that boundary is server-authoritative and cannot be caller-supplied.
    - `HostedPaymentPage`: Vaulted from a hosted payment page: either tokenize-on-payment or the direct ACH vault flow.
    - `VirtualTerminal`: Vaulted from a Virtual Terminal save-on-payment.
    - `Api`: Added through the HTTP add-stored-payment-method endpoint. Covers external API token registration and any in-process operator surface that submits through that same gated endpoint (e.g. the contract add-payment dialog): origin on this boundary is stamped server-side and is never caller-supplied.
  - `readerTokenFingerprint` (string): Dedupe fingerprint for a reader-token-backed (PAN-less) stored method: a one-way SHA-256  digest of the processor reader token that this method's backing vault token carries. Set  only for the reader-token shape (decrypt-and-forward processors such as MagTek DAF, where  the gateway never sees the PAN); `null` for every PAN- or account-backed method. (nullable)
  - `checkFingerprint` (string): Dedupe fingerprint for a check / ACH stored method: a keyed, non-reversible HMAC-SHA-256  digest of the routing number combined with the account number's last four digits. Set only  for the Check shape; `null` for card and reader-token methods. (nullable)
- `contracts` (array<[Contract](https://devportal.demo.winkpg.io/docs/api/models/Contract.md)>): Gets or sets the recurring billing contracts associated with this customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `name` (string): (nullable)
  - `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): (nullable)
  - `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): (nullable)
  - `customerId` (string(uuid))
  - `legacyNumber` (integer(int64)): The contract's legacy numeric key, as used by the v1 API where contracts are identified by an  integer rather than a Guid. Server-owned: stamped once at create from a tenant-scoped counter  and never settable from an inbound payload. (nullable)
  - `customFields` (array<[ContractCustomField](https://devportal.demo.winkpg.io/docs/api/models/ContractCustomField.md)>): The merchant-defined custom field values carried on this contract, or `null`  when it carries none. (nullable)
  - `perBillInvoice` ([ContractPerBillInvoice](https://devportal.demo.winkpg.io/docs/api/models/ContractPerBillInvoice.md))
  - `thresholds` ([ContractThresholds](https://devportal.demo.winkpg.io/docs/api/models/ContractThresholds.md))
  - `aggregates` ([ContractAggregates](https://devportal.demo.winkpg.io/docs/api/models/ContractAggregates.md))
  - `schedule` ([ContractSchedule](https://devportal.demo.winkpg.io/docs/api/models/ContractSchedule.md))
  - `payMethod` ([ContractPayMethod](https://devportal.demo.winkpg.io/docs/api/models/ContractPayMethod.md))
  - `emailNotifications` ([ContractEmailNotifications](https://devportal.demo.winkpg.io/docs/api/models/ContractEmailNotifications.md))
  - `isActive` (boolean)
  - `planId` (string(uuid)): The reusable plan this contract subscribes to for its price, or `null` when  the contract carries its own inline amount. (nullable)
  - `trialEndDate` (string(date-time)): The calendar day the contract's trial period ends, in UTC, or `null` when the  contract has no trial. Nothing is charged before this day: the first charge falls on it (or  on the schedule's first occurrence after it) at the full contract amount. (nullable)
  - `priceChangedAt` (string(date-time)): When an operator last changed what this contract charges per cycle (the plan it subscribes  to, or its inline amount), in UTC, or `null` when that has never happened  since the field existed. Server owned: stamped by the contract update path, never settable  from an inbound payload. (nullable)
  - `deactivationReason` ([ContractDeactivationReason](https://devportal.demo.winkpg.io/docs/api/models/ContractDeactivationReason.md)): Describes why this contract was deactivated. Null when the contract is active  or was never deactivated by the billing engine. Set automatically by the  recurring billing manager and cleared when the contract is reactivated. (nullable)
    Values:
    - `Suspended`: Suspended by the billing engine after consecutive failures exceeded the maxFailCount threshold.
    - `MaxPaymentsReached`: Total execution count (successful + failed) reached maxNumPayments.
    - `MaxSuccessfulBillsReached`: Successful execution count reached maxSuccessfulBills.
    - `MaxAmountReached`: Cumulative amount billed reached maxAmount.
    - `ScheduleExhausted`: The recurrence schedule produced no further occurrences: either the until end date was reached or the recurrence count was exhausted.
    - `Manual`: Manually deactivated by an operator via the UI or API.
    - `CancelledByCardholder`: Cancelled by the cardholder themselves, from the link in an upcoming-charge reminder, with no operator involved.
    - `Paused`: Paused on purpose by an operator, to be resumed later: either by hand, or automatically by the daily billing run once the contract's expected resume date has passed. A pause is a voluntary stop, which is what separates it from Suspended (the billing engine gave up after consecutive failures) and from Manual (deactivated with no intention to resume). The pause itself is described by the contract's pause fields (reason, paused date, expected resume date), which are cleared when the contract resumes.
  - `pauseReason` (string): Why an operator paused this contract, or `null` when it is not paused. Server  owned: written by the pause operation and cleared by every resume, never settable from an  inbound payload. (nullable)
  - `pausedDate` (string(date-time)): When the contract was paused, in UTC, or `null` when it is not paused. Server  owned, stamped by the pause operation and cleared on resume. (nullable)
  - `expectedResumeDate` (string(date-time)): The calendar day, in UTC, on which the daily billing run resumes this contract on its own, or  `null` for a pause with no end date, which only an operator can resume. A  calendar date compared as written, never timezone-converted, the same rule  `trialEndDate` follows: the run that finds this day at or before today resumes  the contract and projects its next charge from that moment. (nullable)
  - `convenienceFeeWaived` (boolean): Whether the cardholder enrolled in this contract on terms that disclosed no convenience fee,  so no scheduled charge under it may carry one. `null` or `false`  means the fee is decided at each charge from the merchant's live configuration, as it always  has been. Server owned: stamped once when a Hosted Payment Page session carrying the  `suppress_convenience_fee` directive creates the contract, never settable from an inbound  payload. (nullable)
  - `upcomingChargeReminderSentForRun` (string(date-time)): The scheduled run, in UTC, that the pre-charge reminder was last sent for, or  `null` when no reminder has been sent. Server owned: written only by the  recurring billing run after the reminder email is queued, never settable from an inbound  payload. (nullable)
  - `description` (string): (nullable)
  - `creationTime` (string(date-time)): The date and time when this entity was created. (nullable)
  - `creatorId` (string(uuid)): The ID of the user who created this entity. (nullable)
  - `lastModificationTime` (string(date-time)): The date and time when this entity was last modified. (nullable)
  - `lastModifierId` (string(uuid)): The ID of the user who last modified this entity. (nullable)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `deleterId` (string(uuid)): The ID of the user who deleted this entity, if it is deleted. (nullable)
  - `deletionTime` (string(date-time)): The date and time when this entity was deleted, if it is deleted. (nullable)
  - `concurrencyStamp` (string): Optimistic-concurrency stamp for the contract, checked independently of the customer that  holds it. A null stamp means "no concurrency check" until the contract is next updated, which  stamps it going forward. (nullable)
- `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): Operational notes attached to the customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `enteredBy` (string(uuid))
  - `timestamp` (string(date-time))
  - `enteredByName` (string): Denormalized display name of the user who created the note.  Populated at creation time from `ICurrentUser` to avoid N+1 lookups when rendering. (nullable)
  - `content` (string): (nullable, min length 0, max length 1000)
- `concurrencyStamp` (string): Gets or sets the concurrency stamp used for optimistic concurrency control. (nullable)

_Example: Move the customer to a new default address_

Replaces the customer's contact details, so the address sent here becomes the customer's only address and its default. The update replaces the whole record rather than merging it: every member this body leaves out is cleared, so stored payment methods, contracts, notes and tags it does not carry are removed from the customer. Start from a read of the customer, send back everything it returned, and change only the address. The merchant cannot change, and the customer's legacy number is never taken from the body. Send the concurrencyStamp from that read in place of the placeholder shown; a stamp that no longer matches is refused with a conflict and nothing is saved.

```json
{
  "concurrencyStamp": "stamp-from-your-most-recent-read",
  "name": "John Doe",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": true,
  "contactDetail": {
    "addresses": [
      {
        "address1": "456 Desert Willow Dr",
        "city": "Tempe",
        "state": "AZ",
        "zip": "85281",
        "country": "USA",
        "isMailing": true,
        "isDefault": true
      }
    ],
    "primaryContactName": "John Doe",
    "emailAddress": "john.doe@example.com",
    "phone": "555-555-0100"
  }
}
```

**Content type:** `text/json`

Schema: [`CustomerUpdateDto`](https://devportal.demo.winkpg.io/docs/api/models/CustomerUpdateDto.md)

Properties:
- `createdFromTemplateId` (string(uuid)): (nullable)
- `name` (string) required: Gets or sets the name of the customer. Must be unique within the owning merchant, compared  case-insensitively. Use `displayName` for a human label that may repeat. (nullable, min length 2, max length 100)
- `displayName` (string): An optional human-readable label for the customer that is deliberately not unique. Supply it  when the recognisable name for two customers is legitimately the same and `name`  carries an external key instead. When present it is what merchants see wherever customers are  listed; when absent those surfaces fall back to `name`. At most 100 characters. (nullable, max length 100)
- `merchantAssignedId` (string): An optional identifier the merchant assigns to the customer as a friendly reference, distinct  from the system Guid `id` and the server-owned legacy number. Surfaces the v1  API's `CustomerId` field. Not an `EditFormField`: it is set through the API rather  than the standard customer form. (nullable, max length 50)
- `merchantId` (string(uuid)) required: Gets or sets the identifier of the merchant that owns this customer.
- `isActive` (boolean): Gets or sets a value indicating whether this customer is active.
- `contactDetail` ([CustomerContactDetail](https://devportal.demo.winkpg.io/docs/api/models/CustomerContactDetail.md)): Gets or sets the customer's contact details (email, phone, address).
  Fields:
  - `primaryContactName` (string): (nullable, max length 100)
  - `emailAddress` (string): The contact's email address. Optional. A value that is not blank must be a valid email address. Conditional: When EmailAddress is not empty. Must be a valid email. (nullable)
  - `phone` (string): The contact's phone number. Optional. A value that is not empty must be a phone number: digits,  with an optional leading `+` and country code, optional parentheses around the area code,  and a space, hyphen or period between groups. Letters, including an extension such as  `x123`, are rejected. (nullable)
  - `fax` (string): The contact's fax number. Optional. Follows the same rule as the phone number. (nullable)
  - `companyUrl` (string): The company's website address. Optional. A value sent without a scheme, such as  `www.example.com`, is stored with `https://` added. A value that starts with  `http://` or `https://` is stored exactly as sent. Any other scheme, and text that is  not a website address, is rejected. (nullable)
  - `addresses` (array<[CustomerAddress](https://devportal.demo.winkpg.io/docs/api/models/CustomerAddress.md)>): The customer's addresses on file. Optional: omit the member, send an empty array, or send  null to record a customer with no address on file. When one or more entries are supplied,  exactly one must be flagged `isDefault`, and every entry must carry `address1`,  `city`, `state` and `zip`. (nullable)
- `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): Gets or sets the collection of tags used to categorize or label this customer. (nullable)
  Fields of each item:
  - `name` (string): (nullable, min length 0, max length 50)
  - `value` (string): (nullable, min length 0, max length 150)
- `storedPaymentMethods` (array<[CustomerStoredPaymentMethod](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethod.md)>): Gets or sets the customer's stored payment methods for recurring or future transactions. (nullable)
  Fields of each item:
  - `id` (string(uuid)): (read only)
  - `paymentMethodType` ([CustomerStoredPaymentMethodType](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethodType.md)): Specifies the type of a stored payment method associated with a customer.
    Values:
    - `Card`
    - `Check`
  - `paymentTokenId` (string(uuid)): (nullable)
  - `cardData` ([CardData](https://devportal.demo.winkpg.io/docs/api/models/CardData.md)): Required: When PaymentMethodType == Card.
  - `checkData` ([CheckData](https://devportal.demo.winkpg.io/docs/api/models/CheckData.md)): Required: When PaymentMethodType == Check.
  - `isDefault` (boolean)
  - `displayName` (string): (nullable, read only)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `customName` (string): Optional user-defined name for this stored payment method (e.g., "Marriott Chase",  "Bank of America Checkcard"). When set, takes priority over the computed display name. (nullable)
  - `initialSchemeTransactionId` (string): The initial (first-in-series) network / scheme transaction id captured from the processor's  authorization response on the cardholder-initiated credential-on-file transaction that stored  this credential. Lets any later transaction (CIT-COF or MIT, any card brand) resolve and echo  the original network transaction id from just the stored token / payment method, without  depending on a StoredCredentialConsent lookup. (nullable)
  - `lastSchemeTransactionId` (string): The most-recent-in-series network / scheme transaction id. At tokenization this equals  `initialSchemeTransactionId`. Card-network rules (Visa 11.1.5, Mastercard 13.1.1)  allow the most recent value in a series to be sent when the original is unavailable, so a later  story can advance this on each subsequent authorization response without losing the first-in-  series anchor. Nullable / non-sensitive as for `initialSchemeTransactionId`. (nullable)
  - `schemeTransactionIdBrand` (string): The card brand at the moment the network transaction id was captured (e.g. "Visa",  "Mastercard", "Discover", "Amex"). Retained because a co-branded card can switch networks  after storage; Mastercard's AltNetTranID handling requires the brand-at-capture to detect the  case where a stored Visa id must be sent in a Mastercard field. Emitting AltNetTranID is out of  scope here: this only preserves the data so the downstream echo work is not precluded.  Nullable / non-sensitive. (nullable)
  - `schemeTransactionIdProcessor` (string): The processor the network transaction id originated from ("tsys" / "fiserv"). The two  processors' response formats differ (TSYS a single 15-char Transaction Identifier; Fiserv  per-brand, whose Visa value can exceed 15 chars including the trailing Validation Code), so the  id is stored opaquely and tagged with its originating processor. Nullable / non-sensitive. (nullable)
  - `publicReference` (string): The externally-emitted, chargeable `PublicReference` of the backing `PaymentToken`  (the opaque `pt_`-prefixed handle) captured when this stored method was minted. Persisted  here so the tokenize-on-payment path can surface it on the transaction response / webhook  without re-reading the token, and so a later charge can round-trip the merchant-facing handle.  Distinct from `paymentTokenId`, which is the internal vault Guid (PAN-correlated,  never emitted). May be `null` on a stored method created before this field existed, until  a one-time platform backfill copies the backing token's handle onto it; the backfill only ever  fills a null and never rewrites an assigned handle. Non-sensitive (an opaque random handle,  not a PAN). (nullable)
  - `origin` ([StoredPaymentMethodOrigin](https://devportal.demo.winkpg.io/docs/api/models/StoredPaymentMethodOrigin.md)): The surface / add-channel this stored payment method was captured through (manual admin,  hosted payment page, virtual terminal, or API). Stamped once at creation and not changed  afterward. (nullable)
    Values:
    - `Unknown`: The add-channel was not recorded. Assigned to methods that predate this field (materialized from a null value) and to any path that did not classify its origin.
    - `ManualAdmin`: Added by an operator through a Customer admin surface that mints the stored method on the customer document directly (the customer edit form's payment-methods dialog, and the create-customer / create-contract-from-transaction dialogs). Note: the contract add-payment dialog submits through the HTTP add endpoint and is therefore recorded as Api, since origin on that boundary is server-authoritative and cannot be caller-supplied.
    - `HostedPaymentPage`: Vaulted from a hosted payment page: either tokenize-on-payment or the direct ACH vault flow.
    - `VirtualTerminal`: Vaulted from a Virtual Terminal save-on-payment.
    - `Api`: Added through the HTTP add-stored-payment-method endpoint. Covers external API token registration and any in-process operator surface that submits through that same gated endpoint (e.g. the contract add-payment dialog): origin on this boundary is stamped server-side and is never caller-supplied.
  - `readerTokenFingerprint` (string): Dedupe fingerprint for a reader-token-backed (PAN-less) stored method: a one-way SHA-256  digest of the processor reader token that this method's backing vault token carries. Set  only for the reader-token shape (decrypt-and-forward processors such as MagTek DAF, where  the gateway never sees the PAN); `null` for every PAN- or account-backed method. (nullable)
  - `checkFingerprint` (string): Dedupe fingerprint for a check / ACH stored method: a keyed, non-reversible HMAC-SHA-256  digest of the routing number combined with the account number's last four digits. Set only  for the Check shape; `null` for card and reader-token methods. (nullable)
- `contracts` (array<[Contract](https://devportal.demo.winkpg.io/docs/api/models/Contract.md)>): Gets or sets the recurring billing contracts associated with this customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `name` (string): (nullable)
  - `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): (nullable)
  - `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): (nullable)
  - `customerId` (string(uuid))
  - `legacyNumber` (integer(int64)): The contract's legacy numeric key, as used by the v1 API where contracts are identified by an  integer rather than a Guid. Server-owned: stamped once at create from a tenant-scoped counter  and never settable from an inbound payload. (nullable)
  - `customFields` (array<[ContractCustomField](https://devportal.demo.winkpg.io/docs/api/models/ContractCustomField.md)>): The merchant-defined custom field values carried on this contract, or `null`  when it carries none. (nullable)
  - `perBillInvoice` ([ContractPerBillInvoice](https://devportal.demo.winkpg.io/docs/api/models/ContractPerBillInvoice.md))
  - `thresholds` ([ContractThresholds](https://devportal.demo.winkpg.io/docs/api/models/ContractThresholds.md))
  - `aggregates` ([ContractAggregates](https://devportal.demo.winkpg.io/docs/api/models/ContractAggregates.md))
  - `schedule` ([ContractSchedule](https://devportal.demo.winkpg.io/docs/api/models/ContractSchedule.md))
  - `payMethod` ([ContractPayMethod](https://devportal.demo.winkpg.io/docs/api/models/ContractPayMethod.md))
  - `emailNotifications` ([ContractEmailNotifications](https://devportal.demo.winkpg.io/docs/api/models/ContractEmailNotifications.md))
  - `isActive` (boolean)
  - `planId` (string(uuid)): The reusable plan this contract subscribes to for its price, or `null` when  the contract carries its own inline amount. (nullable)
  - `trialEndDate` (string(date-time)): The calendar day the contract's trial period ends, in UTC, or `null` when the  contract has no trial. Nothing is charged before this day: the first charge falls on it (or  on the schedule's first occurrence after it) at the full contract amount. (nullable)
  - `priceChangedAt` (string(date-time)): When an operator last changed what this contract charges per cycle (the plan it subscribes  to, or its inline amount), in UTC, or `null` when that has never happened  since the field existed. Server owned: stamped by the contract update path, never settable  from an inbound payload. (nullable)
  - `deactivationReason` ([ContractDeactivationReason](https://devportal.demo.winkpg.io/docs/api/models/ContractDeactivationReason.md)): Describes why this contract was deactivated. Null when the contract is active  or was never deactivated by the billing engine. Set automatically by the  recurring billing manager and cleared when the contract is reactivated. (nullable)
    Values:
    - `Suspended`: Suspended by the billing engine after consecutive failures exceeded the maxFailCount threshold.
    - `MaxPaymentsReached`: Total execution count (successful + failed) reached maxNumPayments.
    - `MaxSuccessfulBillsReached`: Successful execution count reached maxSuccessfulBills.
    - `MaxAmountReached`: Cumulative amount billed reached maxAmount.
    - `ScheduleExhausted`: The recurrence schedule produced no further occurrences: either the until end date was reached or the recurrence count was exhausted.
    - `Manual`: Manually deactivated by an operator via the UI or API.
    - `CancelledByCardholder`: Cancelled by the cardholder themselves, from the link in an upcoming-charge reminder, with no operator involved.
    - `Paused`: Paused on purpose by an operator, to be resumed later: either by hand, or automatically by the daily billing run once the contract's expected resume date has passed. A pause is a voluntary stop, which is what separates it from Suspended (the billing engine gave up after consecutive failures) and from Manual (deactivated with no intention to resume). The pause itself is described by the contract's pause fields (reason, paused date, expected resume date), which are cleared when the contract resumes.
  - `pauseReason` (string): Why an operator paused this contract, or `null` when it is not paused. Server  owned: written by the pause operation and cleared by every resume, never settable from an  inbound payload. (nullable)
  - `pausedDate` (string(date-time)): When the contract was paused, in UTC, or `null` when it is not paused. Server  owned, stamped by the pause operation and cleared on resume. (nullable)
  - `expectedResumeDate` (string(date-time)): The calendar day, in UTC, on which the daily billing run resumes this contract on its own, or  `null` for a pause with no end date, which only an operator can resume. A  calendar date compared as written, never timezone-converted, the same rule  `trialEndDate` follows: the run that finds this day at or before today resumes  the contract and projects its next charge from that moment. (nullable)
  - `convenienceFeeWaived` (boolean): Whether the cardholder enrolled in this contract on terms that disclosed no convenience fee,  so no scheduled charge under it may carry one. `null` or `false`  means the fee is decided at each charge from the merchant's live configuration, as it always  has been. Server owned: stamped once when a Hosted Payment Page session carrying the  `suppress_convenience_fee` directive creates the contract, never settable from an inbound  payload. (nullable)
  - `upcomingChargeReminderSentForRun` (string(date-time)): The scheduled run, in UTC, that the pre-charge reminder was last sent for, or  `null` when no reminder has been sent. Server owned: written only by the  recurring billing run after the reminder email is queued, never settable from an inbound  payload. (nullable)
  - `description` (string): (nullable)
  - `creationTime` (string(date-time)): The date and time when this entity was created. (nullable)
  - `creatorId` (string(uuid)): The ID of the user who created this entity. (nullable)
  - `lastModificationTime` (string(date-time)): The date and time when this entity was last modified. (nullable)
  - `lastModifierId` (string(uuid)): The ID of the user who last modified this entity. (nullable)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `deleterId` (string(uuid)): The ID of the user who deleted this entity, if it is deleted. (nullable)
  - `deletionTime` (string(date-time)): The date and time when this entity was deleted, if it is deleted. (nullable)
  - `concurrencyStamp` (string): Optimistic-concurrency stamp for the contract, checked independently of the customer that  holds it. A null stamp means "no concurrency check" until the contract is next updated, which  stamps it going forward. (nullable)
- `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): Operational notes attached to the customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `enteredBy` (string(uuid))
  - `timestamp` (string(date-time))
  - `enteredByName` (string): Denormalized display name of the user who created the note.  Populated at creation time from `ICurrentUser` to avoid N+1 lookups when rendering. (nullable)
  - `content` (string): (nullable, min length 0, max length 1000)
- `concurrencyStamp` (string): Gets or sets the concurrency stamp used for optimistic concurrency control. (nullable)

_Example: Move the customer to a new default address_

Replaces the customer's contact details, so the address sent here becomes the customer's only address and its default. The update replaces the whole record rather than merging it: every member this body leaves out is cleared, so stored payment methods, contracts, notes and tags it does not carry are removed from the customer. Start from a read of the customer, send back everything it returned, and change only the address. The merchant cannot change, and the customer's legacy number is never taken from the body. Send the concurrencyStamp from that read in place of the placeholder shown; a stamp that no longer matches is refused with a conflict and nothing is saved.

```json
{
  "concurrencyStamp": "stamp-from-your-most-recent-read",
  "name": "John Doe",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": true,
  "contactDetail": {
    "addresses": [
      {
        "address1": "456 Desert Willow Dr",
        "city": "Tempe",
        "state": "AZ",
        "zip": "85281",
        "country": "USA",
        "isMailing": true,
        "isDefault": true
      }
    ],
    "primaryContactName": "John Doe",
    "emailAddress": "john.doe@example.com",
    "phone": "555-555-0100"
  }
}
```

**Content type:** `application/*+json`

Schema: [`CustomerUpdateDto`](https://devportal.demo.winkpg.io/docs/api/models/CustomerUpdateDto.md)

Properties:
- `createdFromTemplateId` (string(uuid)): (nullable)
- `name` (string) required: Gets or sets the name of the customer. Must be unique within the owning merchant, compared  case-insensitively. Use `displayName` for a human label that may repeat. (nullable, min length 2, max length 100)
- `displayName` (string): An optional human-readable label for the customer that is deliberately not unique. Supply it  when the recognisable name for two customers is legitimately the same and `name`  carries an external key instead. When present it is what merchants see wherever customers are  listed; when absent those surfaces fall back to `name`. At most 100 characters. (nullable, max length 100)
- `merchantAssignedId` (string): An optional identifier the merchant assigns to the customer as a friendly reference, distinct  from the system Guid `id` and the server-owned legacy number. Surfaces the v1  API's `CustomerId` field. Not an `EditFormField`: it is set through the API rather  than the standard customer form. (nullable, max length 50)
- `merchantId` (string(uuid)) required: Gets or sets the identifier of the merchant that owns this customer.
- `isActive` (boolean): Gets or sets a value indicating whether this customer is active.
- `contactDetail` ([CustomerContactDetail](https://devportal.demo.winkpg.io/docs/api/models/CustomerContactDetail.md)): Gets or sets the customer's contact details (email, phone, address).
  Fields:
  - `primaryContactName` (string): (nullable, max length 100)
  - `emailAddress` (string): The contact's email address. Optional. A value that is not blank must be a valid email address. Conditional: When EmailAddress is not empty. Must be a valid email. (nullable)
  - `phone` (string): The contact's phone number. Optional. A value that is not empty must be a phone number: digits,  with an optional leading `+` and country code, optional parentheses around the area code,  and a space, hyphen or period between groups. Letters, including an extension such as  `x123`, are rejected. (nullable)
  - `fax` (string): The contact's fax number. Optional. Follows the same rule as the phone number. (nullable)
  - `companyUrl` (string): The company's website address. Optional. A value sent without a scheme, such as  `www.example.com`, is stored with `https://` added. A value that starts with  `http://` or `https://` is stored exactly as sent. Any other scheme, and text that is  not a website address, is rejected. (nullable)
  - `addresses` (array<[CustomerAddress](https://devportal.demo.winkpg.io/docs/api/models/CustomerAddress.md)>): The customer's addresses on file. Optional: omit the member, send an empty array, or send  null to record a customer with no address on file. When one or more entries are supplied,  exactly one must be flagged `isDefault`, and every entry must carry `address1`,  `city`, `state` and `zip`. (nullable)
- `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): Gets or sets the collection of tags used to categorize or label this customer. (nullable)
  Fields of each item:
  - `name` (string): (nullable, min length 0, max length 50)
  - `value` (string): (nullable, min length 0, max length 150)
- `storedPaymentMethods` (array<[CustomerStoredPaymentMethod](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethod.md)>): Gets or sets the customer's stored payment methods for recurring or future transactions. (nullable)
  Fields of each item:
  - `id` (string(uuid)): (read only)
  - `paymentMethodType` ([CustomerStoredPaymentMethodType](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethodType.md)): Specifies the type of a stored payment method associated with a customer.
    Values:
    - `Card`
    - `Check`
  - `paymentTokenId` (string(uuid)): (nullable)
  - `cardData` ([CardData](https://devportal.demo.winkpg.io/docs/api/models/CardData.md)): Required: When PaymentMethodType == Card.
  - `checkData` ([CheckData](https://devportal.demo.winkpg.io/docs/api/models/CheckData.md)): Required: When PaymentMethodType == Check.
  - `isDefault` (boolean)
  - `displayName` (string): (nullable, read only)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `customName` (string): Optional user-defined name for this stored payment method (e.g., "Marriott Chase",  "Bank of America Checkcard"). When set, takes priority over the computed display name. (nullable)
  - `initialSchemeTransactionId` (string): The initial (first-in-series) network / scheme transaction id captured from the processor's  authorization response on the cardholder-initiated credential-on-file transaction that stored  this credential. Lets any later transaction (CIT-COF or MIT, any card brand) resolve and echo  the original network transaction id from just the stored token / payment method, without  depending on a StoredCredentialConsent lookup. (nullable)
  - `lastSchemeTransactionId` (string): The most-recent-in-series network / scheme transaction id. At tokenization this equals  `initialSchemeTransactionId`. Card-network rules (Visa 11.1.5, Mastercard 13.1.1)  allow the most recent value in a series to be sent when the original is unavailable, so a later  story can advance this on each subsequent authorization response without losing the first-in-  series anchor. Nullable / non-sensitive as for `initialSchemeTransactionId`. (nullable)
  - `schemeTransactionIdBrand` (string): The card brand at the moment the network transaction id was captured (e.g. "Visa",  "Mastercard", "Discover", "Amex"). Retained because a co-branded card can switch networks  after storage; Mastercard's AltNetTranID handling requires the brand-at-capture to detect the  case where a stored Visa id must be sent in a Mastercard field. Emitting AltNetTranID is out of  scope here: this only preserves the data so the downstream echo work is not precluded.  Nullable / non-sensitive. (nullable)
  - `schemeTransactionIdProcessor` (string): The processor the network transaction id originated from ("tsys" / "fiserv"). The two  processors' response formats differ (TSYS a single 15-char Transaction Identifier; Fiserv  per-brand, whose Visa value can exceed 15 chars including the trailing Validation Code), so the  id is stored opaquely and tagged with its originating processor. Nullable / non-sensitive. (nullable)
  - `publicReference` (string): The externally-emitted, chargeable `PublicReference` of the backing `PaymentToken`  (the opaque `pt_`-prefixed handle) captured when this stored method was minted. Persisted  here so the tokenize-on-payment path can surface it on the transaction response / webhook  without re-reading the token, and so a later charge can round-trip the merchant-facing handle.  Distinct from `paymentTokenId`, which is the internal vault Guid (PAN-correlated,  never emitted). May be `null` on a stored method created before this field existed, until  a one-time platform backfill copies the backing token's handle onto it; the backfill only ever  fills a null and never rewrites an assigned handle. Non-sensitive (an opaque random handle,  not a PAN). (nullable)
  - `origin` ([StoredPaymentMethodOrigin](https://devportal.demo.winkpg.io/docs/api/models/StoredPaymentMethodOrigin.md)): The surface / add-channel this stored payment method was captured through (manual admin,  hosted payment page, virtual terminal, or API). Stamped once at creation and not changed  afterward. (nullable)
    Values:
    - `Unknown`: The add-channel was not recorded. Assigned to methods that predate this field (materialized from a null value) and to any path that did not classify its origin.
    - `ManualAdmin`: Added by an operator through a Customer admin surface that mints the stored method on the customer document directly (the customer edit form's payment-methods dialog, and the create-customer / create-contract-from-transaction dialogs). Note: the contract add-payment dialog submits through the HTTP add endpoint and is therefore recorded as Api, since origin on that boundary is server-authoritative and cannot be caller-supplied.
    - `HostedPaymentPage`: Vaulted from a hosted payment page: either tokenize-on-payment or the direct ACH vault flow.
    - `VirtualTerminal`: Vaulted from a Virtual Terminal save-on-payment.
    - `Api`: Added through the HTTP add-stored-payment-method endpoint. Covers external API token registration and any in-process operator surface that submits through that same gated endpoint (e.g. the contract add-payment dialog): origin on this boundary is stamped server-side and is never caller-supplied.
  - `readerTokenFingerprint` (string): Dedupe fingerprint for a reader-token-backed (PAN-less) stored method: a one-way SHA-256  digest of the processor reader token that this method's backing vault token carries. Set  only for the reader-token shape (decrypt-and-forward processors such as MagTek DAF, where  the gateway never sees the PAN); `null` for every PAN- or account-backed method. (nullable)
  - `checkFingerprint` (string): Dedupe fingerprint for a check / ACH stored method: a keyed, non-reversible HMAC-SHA-256  digest of the routing number combined with the account number's last four digits. Set only  for the Check shape; `null` for card and reader-token methods. (nullable)
- `contracts` (array<[Contract](https://devportal.demo.winkpg.io/docs/api/models/Contract.md)>): Gets or sets the recurring billing contracts associated with this customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `name` (string): (nullable)
  - `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): (nullable)
  - `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): (nullable)
  - `customerId` (string(uuid))
  - `legacyNumber` (integer(int64)): The contract's legacy numeric key, as used by the v1 API where contracts are identified by an  integer rather than a Guid. Server-owned: stamped once at create from a tenant-scoped counter  and never settable from an inbound payload. (nullable)
  - `customFields` (array<[ContractCustomField](https://devportal.demo.winkpg.io/docs/api/models/ContractCustomField.md)>): The merchant-defined custom field values carried on this contract, or `null`  when it carries none. (nullable)
  - `perBillInvoice` ([ContractPerBillInvoice](https://devportal.demo.winkpg.io/docs/api/models/ContractPerBillInvoice.md))
  - `thresholds` ([ContractThresholds](https://devportal.demo.winkpg.io/docs/api/models/ContractThresholds.md))
  - `aggregates` ([ContractAggregates](https://devportal.demo.winkpg.io/docs/api/models/ContractAggregates.md))
  - `schedule` ([ContractSchedule](https://devportal.demo.winkpg.io/docs/api/models/ContractSchedule.md))
  - `payMethod` ([ContractPayMethod](https://devportal.demo.winkpg.io/docs/api/models/ContractPayMethod.md))
  - `emailNotifications` ([ContractEmailNotifications](https://devportal.demo.winkpg.io/docs/api/models/ContractEmailNotifications.md))
  - `isActive` (boolean)
  - `planId` (string(uuid)): The reusable plan this contract subscribes to for its price, or `null` when  the contract carries its own inline amount. (nullable)
  - `trialEndDate` (string(date-time)): The calendar day the contract's trial period ends, in UTC, or `null` when the  contract has no trial. Nothing is charged before this day: the first charge falls on it (or  on the schedule's first occurrence after it) at the full contract amount. (nullable)
  - `priceChangedAt` (string(date-time)): When an operator last changed what this contract charges per cycle (the plan it subscribes  to, or its inline amount), in UTC, or `null` when that has never happened  since the field existed. Server owned: stamped by the contract update path, never settable  from an inbound payload. (nullable)
  - `deactivationReason` ([ContractDeactivationReason](https://devportal.demo.winkpg.io/docs/api/models/ContractDeactivationReason.md)): Describes why this contract was deactivated. Null when the contract is active  or was never deactivated by the billing engine. Set automatically by the  recurring billing manager and cleared when the contract is reactivated. (nullable)
    Values:
    - `Suspended`: Suspended by the billing engine after consecutive failures exceeded the maxFailCount threshold.
    - `MaxPaymentsReached`: Total execution count (successful + failed) reached maxNumPayments.
    - `MaxSuccessfulBillsReached`: Successful execution count reached maxSuccessfulBills.
    - `MaxAmountReached`: Cumulative amount billed reached maxAmount.
    - `ScheduleExhausted`: The recurrence schedule produced no further occurrences: either the until end date was reached or the recurrence count was exhausted.
    - `Manual`: Manually deactivated by an operator via the UI or API.
    - `CancelledByCardholder`: Cancelled by the cardholder themselves, from the link in an upcoming-charge reminder, with no operator involved.
    - `Paused`: Paused on purpose by an operator, to be resumed later: either by hand, or automatically by the daily billing run once the contract's expected resume date has passed. A pause is a voluntary stop, which is what separates it from Suspended (the billing engine gave up after consecutive failures) and from Manual (deactivated with no intention to resume). The pause itself is described by the contract's pause fields (reason, paused date, expected resume date), which are cleared when the contract resumes.
  - `pauseReason` (string): Why an operator paused this contract, or `null` when it is not paused. Server  owned: written by the pause operation and cleared by every resume, never settable from an  inbound payload. (nullable)
  - `pausedDate` (string(date-time)): When the contract was paused, in UTC, or `null` when it is not paused. Server  owned, stamped by the pause operation and cleared on resume. (nullable)
  - `expectedResumeDate` (string(date-time)): The calendar day, in UTC, on which the daily billing run resumes this contract on its own, or  `null` for a pause with no end date, which only an operator can resume. A  calendar date compared as written, never timezone-converted, the same rule  `trialEndDate` follows: the run that finds this day at or before today resumes  the contract and projects its next charge from that moment. (nullable)
  - `convenienceFeeWaived` (boolean): Whether the cardholder enrolled in this contract on terms that disclosed no convenience fee,  so no scheduled charge under it may carry one. `null` or `false`  means the fee is decided at each charge from the merchant's live configuration, as it always  has been. Server owned: stamped once when a Hosted Payment Page session carrying the  `suppress_convenience_fee` directive creates the contract, never settable from an inbound  payload. (nullable)
  - `upcomingChargeReminderSentForRun` (string(date-time)): The scheduled run, in UTC, that the pre-charge reminder was last sent for, or  `null` when no reminder has been sent. Server owned: written only by the  recurring billing run after the reminder email is queued, never settable from an inbound  payload. (nullable)
  - `description` (string): (nullable)
  - `creationTime` (string(date-time)): The date and time when this entity was created. (nullable)
  - `creatorId` (string(uuid)): The ID of the user who created this entity. (nullable)
  - `lastModificationTime` (string(date-time)): The date and time when this entity was last modified. (nullable)
  - `lastModifierId` (string(uuid)): The ID of the user who last modified this entity. (nullable)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `deleterId` (string(uuid)): The ID of the user who deleted this entity, if it is deleted. (nullable)
  - `deletionTime` (string(date-time)): The date and time when this entity was deleted, if it is deleted. (nullable)
  - `concurrencyStamp` (string): Optimistic-concurrency stamp for the contract, checked independently of the customer that  holds it. A null stamp means "no concurrency check" until the contract is next updated, which  stamps it going forward. (nullable)
- `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): Operational notes attached to the customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `enteredBy` (string(uuid))
  - `timestamp` (string(date-time))
  - `enteredByName` (string): Denormalized display name of the user who created the note.  Populated at creation time from `ICurrentUser` to avoid N+1 lookups when rendering. (nullable)
  - `content` (string): (nullable, min length 0, max length 1000)
- `concurrencyStamp` (string): Gets or sets the concurrency stamp used for optimistic concurrency control. (nullable)

_Example: Move the customer to a new default address_

Replaces the customer's contact details, so the address sent here becomes the customer's only address and its default. The update replaces the whole record rather than merging it: every member this body leaves out is cleared, so stored payment methods, contracts, notes and tags it does not carry are removed from the customer. Start from a read of the customer, send back everything it returned, and change only the address. The merchant cannot change, and the customer's legacy number is never taken from the body. Send the concurrencyStamp from that read in place of the placeholder shown; a stamp that no longer matches is refused with a conflict and nothing is saved.

```json
{
  "concurrencyStamp": "stamp-from-your-most-recent-read",
  "name": "John Doe",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": true,
  "contactDetail": {
    "addresses": [
      {
        "address1": "456 Desert Willow Dr",
        "city": "Tempe",
        "state": "AZ",
        "zip": "85281",
        "country": "USA",
        "isMailing": true,
        "isDefault": true
      }
    ],
    "primaryContactName": "John Doe",
    "emailAddress": "john.doe@example.com",
    "phone": "555-555-0100"
  }
}
```

## Responses

### 200

OK

**Content type:** `application/json`

Schema: [`CustomerDto`](https://devportal.demo.winkpg.io/docs/api/models/CustomerDto.md)

Properties:
- `id` (string(uuid))
- `creationTime` (string(date-time)): The date and time when this entity was created.
- `creatorId` (string(uuid)): The ID of the user who created this entity. (nullable)
- `lastModificationTime` (string(date-time)): The date and time when this entity was last modified. (nullable)
- `lastModifierId` (string(uuid)): The ID of the user who last modified this entity. (nullable)
- `isDeleted` (boolean): Indicates whether this entity has been deleted.
- `deleterId` (string(uuid)): The ID of the user who deleted this entity, if it is deleted. (nullable)
- `deletionTime` (string(date-time)): The date and time when this entity was deleted, if it is deleted. (nullable)
- `createdFromTemplateId` (string(uuid)): The template this record was created from, or `null` for one started blank. Set by the  create-from-template path and by the add/edit page's Load Template action when the record is  saved. (nullable)
- `name` (string): Gets or sets the name of the customer. Unique within the owning merchant, compared  case-insensitively. (nullable)
- `displayName` (string): An optional human-readable label for the customer that is deliberately not unique. Null when  the customer carries no separate label, in which case `name` is what merchants  see wherever customers are listed. (nullable)
- `concurrencyStamp` (string): Gets or sets the concurrency stamp used for optimistic concurrency control. (nullable)
- `tenantId` (string(uuid)): Gets the tenant identifier for multi-tenancy isolation. (nullable, read only)
- `merchantId` (string(uuid)): Gets or sets the identifier of the merchant that owns this customer.
- `isActive` (boolean): Gets or sets a value indicating whether this customer is active.
- `legacyNumber` (integer(int64)): Gets or sets the customer's legacy numeric key, the integer identifier the v1 API resolves  customers by. Server-owned: stamped at create and ignored on every inbound payload. Null on  customers created before the field existed and not yet back-filled by the v1 data migration. (nullable)
- `merchantAssignedId` (string): An optional identifier the merchant assigns to the customer as a friendly reference, distinct  from the system Guid `Id` and the server-owned `legacyNumber`. Surfaces  the v1 API's `CustomerId` field. (nullable)
- `contactDetail` ([CustomerContactDetail](https://devportal.demo.winkpg.io/docs/api/models/CustomerContactDetail.md)): Gets or sets the customer's contact details (email, phone, address).
  Fields:
  - `primaryContactName` (string): (nullable, max length 100)
  - `emailAddress` (string): The contact's email address. Optional. A value that is not blank must be a valid email address. Conditional: When EmailAddress is not empty. Must be a valid email. (nullable)
  - `phone` (string): The contact's phone number. Optional. A value that is not empty must be a phone number: digits,  with an optional leading `+` and country code, optional parentheses around the area code,  and a space, hyphen or period between groups. Letters, including an extension such as  `x123`, are rejected. (nullable)
  - `fax` (string): The contact's fax number. Optional. Follows the same rule as the phone number. (nullable)
  - `companyUrl` (string): The company's website address. Optional. A value sent without a scheme, such as  `www.example.com`, is stored with `https://` added. A value that starts with  `http://` or `https://` is stored exactly as sent. Any other scheme, and text that is  not a website address, is rejected. (nullable)
  - `addresses` (array<[CustomerAddress](https://devportal.demo.winkpg.io/docs/api/models/CustomerAddress.md)>): The customer's addresses on file. Optional: omit the member, send an empty array, or send  null to record a customer with no address on file. When one or more entries are supplied,  exactly one must be flagged `isDefault`, and every entry must carry `address1`,  `city`, `state` and `zip`. (nullable)
- `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): Gets or sets the collection of tags used to categorize or label this customer. (nullable)
  Fields of each item:
  - `name` (string): (nullable, min length 0, max length 50)
  - `value` (string): (nullable, min length 0, max length 150)
- `storedPaymentMethods` (array<[CustomerStoredPaymentMethod](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethod.md)>): Gets or sets the customer's stored payment methods for recurring or future transactions. (nullable)
  Fields of each item:
  - `id` (string(uuid)): (read only)
  - `paymentMethodType` ([CustomerStoredPaymentMethodType](https://devportal.demo.winkpg.io/docs/api/models/CustomerStoredPaymentMethodType.md)): Specifies the type of a stored payment method associated with a customer.
    Values:
    - `Card`
    - `Check`
  - `paymentTokenId` (string(uuid)): (nullable)
  - `cardData` ([CardData](https://devportal.demo.winkpg.io/docs/api/models/CardData.md)): Required: When PaymentMethodType == Card.
  - `checkData` ([CheckData](https://devportal.demo.winkpg.io/docs/api/models/CheckData.md)): Required: When PaymentMethodType == Check.
  - `isDefault` (boolean)
  - `displayName` (string): (nullable, read only)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `customName` (string): Optional user-defined name for this stored payment method (e.g., "Marriott Chase",  "Bank of America Checkcard"). When set, takes priority over the computed display name. (nullable)
  - `initialSchemeTransactionId` (string): The initial (first-in-series) network / scheme transaction id captured from the processor's  authorization response on the cardholder-initiated credential-on-file transaction that stored  this credential. Lets any later transaction (CIT-COF or MIT, any card brand) resolve and echo  the original network transaction id from just the stored token / payment method, without  depending on a StoredCredentialConsent lookup. (nullable)
  - `lastSchemeTransactionId` (string): The most-recent-in-series network / scheme transaction id. At tokenization this equals  `initialSchemeTransactionId`. Card-network rules (Visa 11.1.5, Mastercard 13.1.1)  allow the most recent value in a series to be sent when the original is unavailable, so a later  story can advance this on each subsequent authorization response without losing the first-in-  series anchor. Nullable / non-sensitive as for `initialSchemeTransactionId`. (nullable)
  - `schemeTransactionIdBrand` (string): The card brand at the moment the network transaction id was captured (e.g. "Visa",  "Mastercard", "Discover", "Amex"). Retained because a co-branded card can switch networks  after storage; Mastercard's AltNetTranID handling requires the brand-at-capture to detect the  case where a stored Visa id must be sent in a Mastercard field. Emitting AltNetTranID is out of  scope here: this only preserves the data so the downstream echo work is not precluded.  Nullable / non-sensitive. (nullable)
  - `schemeTransactionIdProcessor` (string): The processor the network transaction id originated from ("tsys" / "fiserv"). The two  processors' response formats differ (TSYS a single 15-char Transaction Identifier; Fiserv  per-brand, whose Visa value can exceed 15 chars including the trailing Validation Code), so the  id is stored opaquely and tagged with its originating processor. Nullable / non-sensitive. (nullable)
  - `publicReference` (string): The externally-emitted, chargeable `PublicReference` of the backing `PaymentToken`  (the opaque `pt_`-prefixed handle) captured when this stored method was minted. Persisted  here so the tokenize-on-payment path can surface it on the transaction response / webhook  without re-reading the token, and so a later charge can round-trip the merchant-facing handle.  Distinct from `paymentTokenId`, which is the internal vault Guid (PAN-correlated,  never emitted). May be `null` on a stored method created before this field existed, until  a one-time platform backfill copies the backing token's handle onto it; the backfill only ever  fills a null and never rewrites an assigned handle. Non-sensitive (an opaque random handle,  not a PAN). (nullable)
  - `origin` ([StoredPaymentMethodOrigin](https://devportal.demo.winkpg.io/docs/api/models/StoredPaymentMethodOrigin.md)): The surface / add-channel this stored payment method was captured through (manual admin,  hosted payment page, virtual terminal, or API). Stamped once at creation and not changed  afterward. (nullable)
    Values:
    - `Unknown`: The add-channel was not recorded. Assigned to methods that predate this field (materialized from a null value) and to any path that did not classify its origin.
    - `ManualAdmin`: Added by an operator through a Customer admin surface that mints the stored method on the customer document directly (the customer edit form's payment-methods dialog, and the create-customer / create-contract-from-transaction dialogs). Note: the contract add-payment dialog submits through the HTTP add endpoint and is therefore recorded as Api, since origin on that boundary is server-authoritative and cannot be caller-supplied.
    - `HostedPaymentPage`: Vaulted from a hosted payment page: either tokenize-on-payment or the direct ACH vault flow.
    - `VirtualTerminal`: Vaulted from a Virtual Terminal save-on-payment.
    - `Api`: Added through the HTTP add-stored-payment-method endpoint. Covers external API token registration and any in-process operator surface that submits through that same gated endpoint (e.g. the contract add-payment dialog): origin on this boundary is stamped server-side and is never caller-supplied.
  - `readerTokenFingerprint` (string): Dedupe fingerprint for a reader-token-backed (PAN-less) stored method: a one-way SHA-256  digest of the processor reader token that this method's backing vault token carries. Set  only for the reader-token shape (decrypt-and-forward processors such as MagTek DAF, where  the gateway never sees the PAN); `null` for every PAN- or account-backed method. (nullable)
  - `checkFingerprint` (string): Dedupe fingerprint for a check / ACH stored method: a keyed, non-reversible HMAC-SHA-256  digest of the routing number combined with the account number's last four digits. Set only  for the Check shape; `null` for card and reader-token methods. (nullable)
- `contracts` (array<[Contract](https://devportal.demo.winkpg.io/docs/api/models/Contract.md)>): Gets or sets the recurring billing contracts associated with this customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `name` (string): (nullable)
  - `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): (nullable)
  - `tags` (array<[EntityTag](https://devportal.demo.winkpg.io/docs/api/models/EntityTag.md)>): (nullable)
  - `customerId` (string(uuid))
  - `legacyNumber` (integer(int64)): The contract's legacy numeric key, as used by the v1 API where contracts are identified by an  integer rather than a Guid. Server-owned: stamped once at create from a tenant-scoped counter  and never settable from an inbound payload. (nullable)
  - `customFields` (array<[ContractCustomField](https://devportal.demo.winkpg.io/docs/api/models/ContractCustomField.md)>): The merchant-defined custom field values carried on this contract, or `null`  when it carries none. (nullable)
  - `perBillInvoice` ([ContractPerBillInvoice](https://devportal.demo.winkpg.io/docs/api/models/ContractPerBillInvoice.md))
  - `thresholds` ([ContractThresholds](https://devportal.demo.winkpg.io/docs/api/models/ContractThresholds.md))
  - `aggregates` ([ContractAggregates](https://devportal.demo.winkpg.io/docs/api/models/ContractAggregates.md))
  - `schedule` ([ContractSchedule](https://devportal.demo.winkpg.io/docs/api/models/ContractSchedule.md))
  - `payMethod` ([ContractPayMethod](https://devportal.demo.winkpg.io/docs/api/models/ContractPayMethod.md))
  - `emailNotifications` ([ContractEmailNotifications](https://devportal.demo.winkpg.io/docs/api/models/ContractEmailNotifications.md))
  - `isActive` (boolean)
  - `planId` (string(uuid)): The reusable plan this contract subscribes to for its price, or `null` when  the contract carries its own inline amount. (nullable)
  - `trialEndDate` (string(date-time)): The calendar day the contract's trial period ends, in UTC, or `null` when the  contract has no trial. Nothing is charged before this day: the first charge falls on it (or  on the schedule's first occurrence after it) at the full contract amount. (nullable)
  - `priceChangedAt` (string(date-time)): When an operator last changed what this contract charges per cycle (the plan it subscribes  to, or its inline amount), in UTC, or `null` when that has never happened  since the field existed. Server owned: stamped by the contract update path, never settable  from an inbound payload. (nullable)
  - `deactivationReason` ([ContractDeactivationReason](https://devportal.demo.winkpg.io/docs/api/models/ContractDeactivationReason.md)): Describes why this contract was deactivated. Null when the contract is active  or was never deactivated by the billing engine. Set automatically by the  recurring billing manager and cleared when the contract is reactivated. (nullable)
    Values:
    - `Suspended`: Suspended by the billing engine after consecutive failures exceeded the maxFailCount threshold.
    - `MaxPaymentsReached`: Total execution count (successful + failed) reached maxNumPayments.
    - `MaxSuccessfulBillsReached`: Successful execution count reached maxSuccessfulBills.
    - `MaxAmountReached`: Cumulative amount billed reached maxAmount.
    - `ScheduleExhausted`: The recurrence schedule produced no further occurrences: either the until end date was reached or the recurrence count was exhausted.
    - `Manual`: Manually deactivated by an operator via the UI or API.
    - `CancelledByCardholder`: Cancelled by the cardholder themselves, from the link in an upcoming-charge reminder, with no operator involved.
    - `Paused`: Paused on purpose by an operator, to be resumed later: either by hand, or automatically by the daily billing run once the contract's expected resume date has passed. A pause is a voluntary stop, which is what separates it from Suspended (the billing engine gave up after consecutive failures) and from Manual (deactivated with no intention to resume). The pause itself is described by the contract's pause fields (reason, paused date, expected resume date), which are cleared when the contract resumes.
  - `pauseReason` (string): Why an operator paused this contract, or `null` when it is not paused. Server  owned: written by the pause operation and cleared by every resume, never settable from an  inbound payload. (nullable)
  - `pausedDate` (string(date-time)): When the contract was paused, in UTC, or `null` when it is not paused. Server  owned, stamped by the pause operation and cleared on resume. (nullable)
  - `expectedResumeDate` (string(date-time)): The calendar day, in UTC, on which the daily billing run resumes this contract on its own, or  `null` for a pause with no end date, which only an operator can resume. A  calendar date compared as written, never timezone-converted, the same rule  `trialEndDate` follows: the run that finds this day at or before today resumes  the contract and projects its next charge from that moment. (nullable)
  - `convenienceFeeWaived` (boolean): Whether the cardholder enrolled in this contract on terms that disclosed no convenience fee,  so no scheduled charge under it may carry one. `null` or `false`  means the fee is decided at each charge from the merchant's live configuration, as it always  has been. Server owned: stamped once when a Hosted Payment Page session carrying the  `suppress_convenience_fee` directive creates the contract, never settable from an inbound  payload. (nullable)
  - `upcomingChargeReminderSentForRun` (string(date-time)): The scheduled run, in UTC, that the pre-charge reminder was last sent for, or  `null` when no reminder has been sent. Server owned: written only by the  recurring billing run after the reminder email is queued, never settable from an inbound  payload. (nullable)
  - `description` (string): (nullable)
  - `creationTime` (string(date-time)): The date and time when this entity was created. (nullable)
  - `creatorId` (string(uuid)): The ID of the user who created this entity. (nullable)
  - `lastModificationTime` (string(date-time)): The date and time when this entity was last modified. (nullable)
  - `lastModifierId` (string(uuid)): The ID of the user who last modified this entity. (nullable)
  - `isDeleted` (boolean): Indicates whether this entity has been deleted. (nullable)
  - `deleterId` (string(uuid)): The ID of the user who deleted this entity, if it is deleted. (nullable)
  - `deletionTime` (string(date-time)): The date and time when this entity was deleted, if it is deleted. (nullable)
  - `concurrencyStamp` (string): Optimistic-concurrency stamp for the contract, checked independently of the customer that  holds it. A null stamp means "no concurrency check" until the contract is next updated, which  stamps it going forward. (nullable)
- `entityVersion` (integer(int32)): Gets the entity version, incremented on each modification for optimistic concurrency. (read only)
- `extraProperties` (object): Gets the extra properties dictionary for extensible data storage. (nullable, read only)
- `notes` (array<[EntityNote](https://devportal.demo.winkpg.io/docs/api/models/EntityNote.md)>): Gets or sets operational notes attached to the customer. (nullable)
  Fields of each item:
  - `id` (string(uuid))
  - `enteredBy` (string(uuid))
  - `timestamp` (string(date-time))
  - `enteredByName` (string): Denormalized display name of the user who created the note.  Populated at creation time from `ICurrentUser` to avoid N+1 lookups when rendering. (nullable)
  - `content` (string): (nullable, min length 0, max length 1000)

_Example: Customer with a stored card_

An active customer with contact details, a mailing address and one stored Visa card set as the default. Charge the stored card by its publicReference.

```json
{
  "id": "2a7c9e14-6b3d-4f58-9a0c-1d2e3f4a5b01",
  "name": "Jordan Lee",
  "concurrencyStamp": "9a5c3e7f1b2d4c6e8f0a1b2c3d4e5f6a",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": true,
  "merchantAssignedId": "CUST-1001",
  "contactDetail": {
    "addresses": [
      {
        "id": "2a7c9e14-6b3d-4f58-9a0c-1d2e3f4a5b03",
        "address1": "200 Elm St",
        "address2": "",
        "city": "Tempe",
        "state": "AZ",
        "province": "",
        "zip": "85281",
        "postalCode": "",
        "country": "USA",
        "isMailing": true,
        "isDefault": true
      }
    ],
    "primaryContactName": "Jordan Lee",
    "emailAddress": "jordan.lee@example.com",
    "phone": "555-555-0123",
    "fax": "",
    "companyUrl": ""
  },
  "tags": [
    {
      "name": "wholesale"
    }
  ],
  "storedPaymentMethods": [
    {
      "id": "2a7c9e14-6b3d-4f58-9a0c-1d2e3f4a5b02",
      "paymentMethodType": "Card",
      "paymentTokenId": "00000000-0000-0000-0000-00000000a001",
      "cardData": {
        "cardNumber": "************1111",
        "last4CardNumber": 1111,
        "expirationMonth": 12,
        "expirationYear": 2030,
        "binData": {
          "bin": 411111,
          "issuedEntity": "Personal",
          "brand": "Visa",
          "type": "Credit",
          "panLength": 16,
          "fundingSource": "Credit"
        },
        "nameOnCard": "Jordan Lee",
        "entryMode": "Unknown",
        "cvPresence": "None"
      },
      "isDefault": true,
      "displayName": "Visa Credit ending in 1111",
      "isDeleted": false,
      "publicReference": "pt_SampleRefDocsExampleOnly",
      "origin": "Api"
    }
  ],
  "contracts": [ ],
  "entityVersion": 0,
  "extraProperties": { },
  "notes": [ ],
  "isDeleted": false,
  "lastModificationTime": "2026-01-12T16:05:00.0000000+00:00",
  "creationTime": "2025-09-08T19:20:00.0000000+00:00"
}
```

### 403

Forbidden

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

### 401

Unauthorized

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

### 400

Bad Request

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

_Example: Request failed validation_

One or more fields were rejected before any rule ran. error.code is null on the envelope and the causes are in validationErrors, one entry per failure. An entry carries code when the validator declared a publishable one, and memberPaths when the full path says more than members does (an element inside a collection, for example). Both keys are omitted when they would add nothing.

```json
{
  "error": {
    "code": "null",
    "message": "Your request is not valid!",
    "details": "The following errors were detected during validation.",
    "data": {
      "correlationId": "0123456789abcdef0123456789abcdef"
    },
    "validationErrors": [
      {
        "message": "'Amount' must be greater than 0.",
        "members": [
          "amount"
        ]
      },
      {
        "message": "The card has expired.",
        "members": [
          "expirationDate"
        ],
        "code": "CardData:CardExpired"
      },
      {
        "message": "'Value' must not be empty.",
        "members": [
          "value"
        ],
        "memberPaths": [
          "customFields[2].value"
        ]
      }
    ]
  }
}
```

### 404

Not Found

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

_Example: Resource not found_

The id in the path names no record the caller can see. Most resources answer with a null error.code and a message naming the resource type and the id; a resource that publishes a not-found code in the catalog above carries it in error.code instead, so check for one before matching on the message.

```json
{
  "error": {
    "code": "null",
    "message": "There is no entity Transaction with id = 7d1f3a52-0c4e-4b8a-9e21-5a6b7c8d9e00!",
    "details": "null",
    "data": {
      "correlationId": "0123456789abcdef0123456789abcdef"
    },
    "validationErrors": "null"
  }
}
```

### 409

Conflict. The `concurrencyStamp` sent is not the resource's current one: the resource changed after it was read. Read the resource again and retry with the `concurrencyStamp` it returns. The body carries the standard error envelope.

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

### 501

Not Implemented

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

### 500

Internal Server Error

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

### default

The request failed. The body carries the standard error envelope: a machine-readable `error.code`, a human-readable `error.message`, and `error.validationErrors` when the failure was a validation rejection. The [error reference](https://devportal.demo.winkpg.io/docs/errors.md) lists the values `error.code` can take.

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

_Example: Business rule refused the request_

The request was understood and rejected by a platform rule. This is the shape that carries a code from the catalog above, so branch on error.code rather than on the message text. The HTTP status is the one listed against the code.

```json
{
  "error": {
    "code": "Transactions:OperationNotAllowed",
    "message": "The operation 'Void' is not allowed on a Sale transaction with result 'Approved' and settlement state 'Settled'.",
    "details": "null",
    "data": {
      "correlationId": "0123456789abcdef0123456789abcdef"
    },
    "validationErrors": "null"
  }
}
```

### 429

The request was refused because a rate limit was exceeded, or because something a later retry can clear stopped it. A rate limit refusal carries an `application/problem+json` body: wait at least the interval `Retry-After` names before retrying, then back off. Limits are tuned per deployment, so read the allowance from the response headers rather than assuming a fixed ceiling. Any other refusal carries the standard error envelope as `application/json`, and its `error.code` names the cause.

**Content type:** `application/problem+json`

Schema: [`RateLimitProblemDetails`](https://devportal.demo.winkpg.io/docs/api/models/RateLimitProblemDetails.md)

Properties:
- `type` (string) required: The problem type identifier. Always the same value: the failure is the status code itself,  so there is no sub-type for a caller to branch on. (nullable)
- `title` (string) required: A short, human-readable summary of the problem type. (nullable)
- `status` (integer(int32)) required: The HTTP status code, repeated in the body as the problem-details format defines.
- `detail` (string) required: A human-readable explanation of this occurrence of the problem. (nullable)
- `retryAfterSeconds` (integer(int32)) required: How long to wait before retrying, in whole seconds, carrying the same figure as the  `Retry-After` header. Always at least one: a value of zero would invite an immediate  retry that is certain to be rejected again.

**Content type:** `application/json`

Schema: [`RemoteServiceErrorResponse`](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorResponse.md)

Properties:
- `error` ([RemoteServiceErrorInfo](https://devportal.demo.winkpg.io/docs/api/models/RemoteServiceErrorInfo.md))

## Example request

Every block below sends the same request. Replace {{BASE_URL}} with the address of the API you are calling and {{API_KEY}} with your own key.

The request body is a CustomerUpdateDto. See the Request body section below for its fields.

### cURL

```bash
curl -X PUT "{{BASE_URL}}/api/customers/{id}" \
  -H "api-key: {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
  "concurrencyStamp": "stamp-from-your-most-recent-read",
  "name": "John Doe",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": true,
  "contactDetail": {
    "addresses": [
      {
        "address1": "456 Desert Willow Dr",
        "city": "Tempe",
        "state": "AZ",
        "zip": "85281",
        "country": "USA",
        "isMailing": true,
        "isDefault": true
      }
    ],
    "primaryContactName": "John Doe",
    "emailAddress": "john.doe@example.com",
    "phone": "555-555-0100"
  }
}'
```

### PowerShell

```powershell
$headers = @{
    'api-key' = '{{API_KEY}}'
}

$body = @'
{
  "concurrencyStamp": "stamp-from-your-most-recent-read",
  "name": "John Doe",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": true,
  "contactDetail": {
    "addresses": [
      {
        "address1": "456 Desert Willow Dr",
        "city": "Tempe",
        "state": "AZ",
        "zip": "85281",
        "country": "USA",
        "isMailing": true,
        "isDefault": true
      }
    ],
    "primaryContactName": "John Doe",
    "emailAddress": "john.doe@example.com",
    "phone": "555-555-0100"
  }
}
'@

$response = Invoke-RestMethod -Method PUT -Uri '{{BASE_URL}}/api/customers/{id}' `
    -Headers $headers -ContentType 'application/json' -Body $body
```

### TypeScript (SDK)

```bash
npm install @winkpg/winkpg-api
```

```typescript
import { Configuration, CustomersApi } from '@winkpg/winkpg-api';

const api = new CustomersApi(new Configuration({
  basePath: '{{BASE_URL}}',
  apiKey: '{{API_KEY}}',
}));

const { data } = await api.customersUpdate("3fa85f64-5717-4562-b3fc-2c963f66afa6", {
  "concurrencyStamp": "stamp-from-your-most-recent-read",
  "name": "John Doe",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": true,
  "contactDetail": {
    "addresses": [
      {
        "address1": "456 Desert Willow Dr",
        "city": "Tempe",
        "state": "AZ",
        "zip": "85281",
        "country": "USA",
        "isMailing": true,
        "isDefault": true
      }
    ],
    "primaryContactName": "John Doe",
    "emailAddress": "john.doe@example.com",
    "phone": "555-555-0100"
  }
});
```

### TypeScript (raw HTTP)

```typescript
const response = await fetch('{{BASE_URL}}/api/customers/{id}', {
  method: 'PUT',
  headers: {
    "api-key": "{{API_KEY}}",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "concurrencyStamp": "stamp-from-your-most-recent-read",
    "name": "John Doe",
    "merchantId": "00000000-0000-0000-0000-000000000001",
    "isActive": true,
    "contactDetail": {
      "addresses": [
        {
          "address1": "456 Desert Willow Dr",
          "city": "Tempe",
          "state": "AZ",
          "zip": "85281",
          "country": "USA",
          "isMailing": true,
          "isDefault": true
        }
      ],
      "primaryContactName": "John Doe",
      "emailAddress": "john.doe@example.com",
      "phone": "555-555-0100"
    }
  }),
});

const data = await response.json();
```

### C# (SDK)

```bash
dotnet add package WinkPg.Api.Client
```

```csharp
using WinkPg.Api.Client.Api;
using WinkPg.Api.Client.Client;
using System.Text.Json;

var config = new Configuration { BasePath = "{{BASE_URL}}" };
config.AddApiKey("api-key", "{{API_KEY}}");

var api = new CustomersApi(config);
var body = JsonSerializer.Deserialize<CustomerUpdateDto>("""
    {
      "concurrencyStamp": "stamp-from-your-most-recent-read",
      "name": "John Doe",
      "merchantId": "00000000-0000-0000-0000-000000000001",
      "isActive": true,
      "contactDetail": {
        "addresses": [
          {
            "address1": "456 Desert Willow Dr",
            "city": "Tempe",
            "state": "AZ",
            "zip": "85281",
            "country": "USA",
            "isMailing": true,
            "isDefault": true
          }
        ],
        "primaryContactName": "John Doe",
        "emailAddress": "john.doe@example.com",
        "phone": "555-555-0100"
      }
    }
    """);

var result = await api.CustomersUpdateAsync(Guid.Parse("3fa85f64-5717-4562-b3fc-2c963f66afa6"), body);
```

### C# (raw HTTP)

```csharp
using System.Text;

using var http = new HttpClient { BaseAddress = new Uri("{{BASE_URL}}") };

var request = new HttpRequestMessage(new HttpMethod("PUT"), "/api/customers/{id}");
request.Headers.Add("api-key", "{{API_KEY}}");

request.Content = new StringContent("""
    {
      "concurrencyStamp": "stamp-from-your-most-recent-read",
      "name": "John Doe",
      "merchantId": "00000000-0000-0000-0000-000000000001",
      "isActive": true,
      "contactDetail": {
        "addresses": [
          {
            "address1": "456 Desert Willow Dr",
            "city": "Tempe",
            "state": "AZ",
            "zip": "85281",
            "country": "USA",
            "isMailing": true,
            "isDefault": true
          }
        ],
        "primaryContactName": "John Doe",
        "emailAddress": "john.doe@example.com",
        "phone": "555-555-0100"
      }
    }
    """, Encoding.UTF8, "application/json");

var response = await http.SendAsync(request);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
```

### Python (SDK)

```bash
pip install winkpg-api
```

```python
import winkpg_api

configuration = winkpg_api.Configuration(host="{{BASE_URL}}")
configuration.api_key["ApiKey"] = "{{API_KEY}}"

with winkpg_api.ApiClient(configuration) as client:
    api = winkpg_api.CustomersApi(client)
    body = winkpg_api.CustomerUpdateDto.from_dict({
      "concurrencyStamp": "stamp-from-your-most-recent-read",
      "name": "John Doe",
      "merchantId": "00000000-0000-0000-0000-000000000001",
      "isActive": True,
      "contactDetail": {
        "addresses": [
          {
            "address1": "456 Desert Willow Dr",
            "city": "Tempe",
            "state": "AZ",
            "zip": "85281",
            "country": "USA",
            "isMailing": True,
            "isDefault": True
          }
        ],
        "primaryContactName": "John Doe",
        "emailAddress": "john.doe@example.com",
        "phone": "555-555-0100"
      }
    })
    result = api.customers_update("3fa85f64-5717-4562-b3fc-2c963f66afa6", body)
```

### Python (raw HTTP)

```bash
pip install requests
```

```python
import requests

headers = {
    "api-key": "{{API_KEY}}",
    "Content-Type": "application/json",
}

body = {
  "concurrencyStamp": "stamp-from-your-most-recent-read",
  "name": "John Doe",
  "merchantId": "00000000-0000-0000-0000-000000000001",
  "isActive": True,
  "contactDetail": {
    "addresses": [
      {
        "address1": "456 Desert Willow Dr",
        "city": "Tempe",
        "state": "AZ",
        "zip": "85281",
        "country": "USA",
        "isMailing": True,
        "isDefault": True
      }
    ],
    "primaryContactName": "John Doe",
    "emailAddress": "john.doe@example.com",
    "phone": "555-555-0100"
  }
}

response = requests.request(
    "PUT",
    "{{BASE_URL}}/api/customers/{id}",
    headers=headers,
    json=body,
)
response.raise_for_status()
data = response.json()
```

## See also

- [All documentation](https://devportal.demo.winkpg.io/llms.txt): the machine-readable index of every public page on this site.
