"""API settings."""
input APISettingsInput {
  """The origins allowed to call the API, comma separated."""
  allowedOrigins: String
  """The API version in use."""
  apiVersion: String
  """True to switch the API on."""
  enableAPI: Boolean
  """True to switch webhooks on."""
  enableWebhooks: Boolean
  """The most requests allowed per hour."""
  rateLimitPerHour: String
  """The most requests allowed per minute."""
  rateLimitPerMinute: String
  """True when requests must carry an API key."""
  requireApiKeys: Boolean
  """How many times a failed webhook is retried."""
  webhookRetryAttempts: String
}

"""Accepts an invitation to a customer account."""
input AcceptCustomerInviteInput {
  """
  Ignored. The inviter already entered the name, and an accept never writes one.
  """
  firstName: String
  """Ignored. See `firstName`."""
  lastName: String
  """The invitation token from the invite link."""
  token: String!
}

"""Controls which quotes are visible based on organizational hierarchy"""
enum AccessMode {
  """Every record in the organization."""
  ALL
  """Only records that belong to the caller."""
  MINE
  """Records that belong to the caller and the people who report to them."""
  TEAM
}

"""Accounting settings."""
input AccountingSettingsInput {
  """
  What the aging of receivables is counted from: DUE_DATE, the default, counts days past due, and INVOICE_DATE counts days since the invoice.
  """
  agingBasis: String
  """
  The upper edges of the overdue bands, strictly ascending. For example 30, 60 and 90 give current, 1-30, 31-60, 61-90 and 90+, the default.
  """
  agingBucketDays: [Int!]
  """The organization's base currency."""
  baseCurrency: String
  """The default accounting method."""
  defaultAccountingMethod: String
  """True to allow more than one currency."""
  enableMultiCurrency: Boolean
  """When the fiscal year starts."""
  fiscalYearStart: String
  """How tax is worked out by default."""
  taxCalculationMethod: String
}

"""Counts of things waiting for someone to act."""
type ActionQueue {
  """How many quotes are drafts."""
  draftQuotes: Int!
  """
  How many confirmed orders still have items to ship. An invoiced order counts until everything on it has shipped; short-closed quantities are left out. The salesOrders filter awaitingFulfilment returns the same orders.
  """
  ordersAwaitingFulfilment: Int!
  """How many invoices are overdue."""
  overdueInvoices: Int!
  """How many items are waiting for approval."""
  pendingApprovals: Int!
}

"""How many events one person caused."""
type ActivityActorCount {
  """The ID of the person."""
  actorId: String!
  """The name of the person."""
  actorName: String
  """The role of the person."""
  actorRole: String
  """How many events."""
  count: Int!
}

"""A count for one key."""
type ActivityCount {
  """How many events."""
  count: Int!
  """The action or kind of record."""
  key: String!
}

"""One entry of a record's activity history."""
type ActivityLog {
  """What was done."""
  action: String!
  """The fields that changed, with their old and new values."""
  changes: JSON
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """The user who did it."""
  user: ActivityUser
}

"""Figures about the activity log."""
type ActivityLogAnalytics {
  """How many different people caused events."""
  activeActors: Int!
  """Events by action."""
  byAction: [ActivityCount!]!
  """Events by person."""
  byActor: [ActivityActorCount!]!
  """Events by kind of record."""
  byEntityType: [ActivityCount!]!
  """How many events there were today."""
  eventsToday: Int!
  """Events by day."""
  timeSeries: [ActivityTimeSeriesPoint!]!
  """How many events there were."""
  totalEvents: Int!
}

"""One event in the activity log."""
type ActivityLogEntry {
  """What was done."""
  action: String!
  """The email address of the person."""
  actorEmail: String
  """The ID of the person who did it."""
  actorId: String
  """The name of the person."""
  actorName: String
  """The role of the person."""
  actorRole: String
  """
  What changed, as JSON with before, after, fields, summary, label and metadata.
  """
  changes: JSON
  "When the record was created."
  createdAt: DateTime!
  """The ID of the record."""
  entityId: String
  """The name of the record."""
  entityLabel: String
  """The kind of record it was done to."""
  entityType: String!
  "The unique ID of this record."
  id: String!
  """The IP address it came from."""
  ipAddress: String
  """Where the event came from."""
  source: ActivityLogSource!
  """A short description of the event."""
  summary: String
  """The browser or app it came from."""
  userAgent: String
}

"""The values the activity log can be filtered by."""
type ActivityLogFacets {
  """The actions that occur."""
  actions: [String!]!
  """The kinds of record that occur."""
  entityTypes: [String!]!
}

"""Filters for the activity log."""
input ActivityLogFilterInput {
  """Only events with this action."""
  action: String
  """Only events by this person."""
  actorId: String
  """Only events on or after this date."""
  dateFrom: DateTime
  """Only events on or before this date."""
  dateTo: DateTime
  """Only events on this kind of record."""
  entityType: String
  "Text to search for."
  search: String
  """Only events from this source."""
  source: ActivityLogSource
}

"""
Origin of an activity entry: AUDIT = business data changes, AUTH = authentication events
"""
enum ActivityLogSource {
  """Entries from the audit log of changes to records."""
  AUDIT
  """Entries from the sign-in and account security log."""
  AUTH
}

"""A page of activity log events."""
type ActivityLogsResponse {
  """The events on this page."""
  items: [ActivityLogEntry!]!
  """The page number."""
  page: Int!
  """How many events per page."""
  pageSize: Int!
  """How many events match in all."""
  total: Int!
}

"""Events on one day."""
type ActivityTimeSeriesPoint {
  """How many of them were sign in events."""
  authCount: Int!
  """How many events."""
  count: Int!
  """The day, as YYYY-MM-DD in UTC."""
  date: String!
}

"""A user named in an activity log entry."""
type ActivityUser {
  "Email address."
  email: String!
  """The user's first name."""
  firstName: String!
  "The unique ID of this record."
  id: ID!
  """The user's last name."""
  lastName: String!
}

"""Adds a currency to the organization."""
input AddCurrencyInput {
  "ISO 4217 currency code."
  currencyCode: String!
  """
  How much of the base currency one unit of this currency is worth: 1 currency = rate base. It must be greater than zero.
  """
  exchangeRate: Float!
}

"""Adds a contact to the buyer's account."""
input AddMobileContactInput {
  """The person's department."""
  department: String
  "Email address."
  email: String
  """The person's first name."""
  firstName: String
  """The person's last name."""
  lastName: String
  """The person's full name, for callers that send one name."""
  name: String
  "Phone number."
  phone: String
  """The person's job title."""
  title: String
  """The person's WhatsApp number."""
  whatsapp: String
}

"""Adds a custom domain to the organization's portal."""
input AddOrganizationDomainInput {
  """Full hostname to map to this organization, e.g. orders.acme.com"""
  hostname: String!
}

"""A new value of an attribute."""
input AddProductAttributeValueInput {
  """The attribute, in any spelling."""
  attributeKey: String!
  """The new value."""
  value: String!
}

"""Adds an item to the cart."""
input AddToCartInput {
  """
  Buyer consent: if this item becomes unavailable, may fulfillment ship a manually-picked substitute instead? Set once at cart time; carries forward automatically through Quote/SalesOrder/Invoice.
  """
  acceptAlternativeIfUnavailable: Boolean
  """CAS guard: the cart revision this mutation was read against."""
  expectedRevision: Int
  """A note on the line."""
  notes: String
  """Client-minted id for replay-safety (same id+payload = no-op success)."""
  operationId: String
  "The ID of the product."
  productId: ID!
  """The quantity to add. Must be greater than zero."""
  quantity: Float!
  "The ID of the unit of measure."
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
}

"""A postal address."""
type Address {
  """The first line of the address."""
  addressLine1: String
  """The second line of the address."""
  addressLine2: String
  """The city."""
  city: String
  """The email address of the contact at the address."""
  contactEmail: String
  """The name of the contact at the address."""
  contactName: String
  """The phone number of the contact at the address."""
  contactPhone: String
  """The map coordinates, as JSON."""
  coordinates: JSON
  """The country."""
  country: String
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """Delivery or access instructions."""
  instructions: String
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """True when the one address serves both billing and delivery."""
  isDualPurpose: Boolean!
  """A label for the address, such as Head office."""
  label: String
  """A nearby landmark."""
  landmark: String
  """The latitude of the address on the map."""
  latitude: Float
  """The longitude of the address on the map."""
  longitude: Float
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes about the address."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  "The ID of the partner."
  partnerId: String
  """The postal code."""
  postalCode: String
  """Whether the address is the primary or a secondary one."""
  priority: String
  """Whether the address is for a customer or a vendor role."""
  role: String
  """The state or region."""
  state: String
  """The first line of the street address."""
  street1: String
  """The second line of the street address."""
  street2: String
  """The kind of address, for example billing or shipping."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""Priority of address (PRIMARY, SECONDARY, BILLING, SHIPPING)"""
enum AddressPriority {
  """The address used for billing."""
  BILLING
  """The main address."""
  PRIMARY
  """An additional address."""
  SECONDARY
  """The address used for shipping."""
  SHIPPING
}

"""
Type of address (BILLING, SHIPPING, WAREHOUSE, OFFICE, HOME, PICKUP, DELIVERY, RETURN)
"""
enum AddressType {
  """A billing address."""
  BILLING
  """A delivery address."""
  DELIVERY
  """A home address."""
  HOME
  """An office address."""
  OFFICE
  """A pickup address."""
  PICKUP
  """An address that returns are sent to."""
  RETURN
  """A shipping address."""
  SHIPPING
  """A warehouse address."""
  WAREHOUSE
}

"""An audited correction to a bank account's balance, as a signed amount."""
input AdjustBankAccountBalanceInput {
  """
  Signed amount in the account's currency: positive adds, negative reduces. Must be non-zero.
  """
  delta: Float!
  """Why the balance is being corrected — recorded on the audit row."""
  reason: String!
}

"""A correction to the stock of one variant in one warehouse."""
input AdjustInventoryInput {
  """The signed change in quantity: positive adds, negative removes."""
  adjustmentQuantity: Float!
  """The batch to adjust."""
  batchNumber: String
  """
  A unique key. Sending the same key again returns the adjustment already made instead of a second one.
  """
  idempotencyKey: String
  """
  The unit cost the stock should carry after the adjustment. It replaces the cost rather than blending into it. Leave out to keep the cost, since 0 is a real cost.
  """
  newUnitCost: Float
  """Notes about the adjustment."""
  notes: String
  "The ID of the product."
  productId: ID!
  """Why the stock is being adjusted."""
  reason: String!
  """The serial number to adjust."""
  serialNumber: String
  "The ID of the unit of measure."
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
  "The ID of the warehouse."
  warehouseId: ID!
}

"""The admin dashboard."""
type AdminDashboard {
  """The integrations and their sync state."""
  integrations: [AdminIntegration!]!
  """How the modules are used."""
  moduleUsage: AdminModuleUsage!
  """Notification counts."""
  notifications: AdminNotifications!
  """Security figures."""
  securityMetrics: AdminSecurityMetrics!
  """How the system is performing."""
  systemHealth: AdminSystemHealth!
  """Headline system figures."""
  systemOverview: AdminSystemOverview!
  """How active users are."""
  userActivity: AdminUserActivity!
}

"""How the finance module is used."""
type AdminFinanceModuleUsage {
  """How many credit notes are active."""
  creditNotesActive: Int!
  """How many invoices are overdue."""
  overdueInvoices: Int!
  """How many payments are pending."""
  pendingPayments: Int!
}

"""An integration and its sync state."""
type AdminIntegration {
  """When it last synced."""
  lastSync: DateTime!
  """The name of the integration."""
  name: String!
  """How many records it synced."""
  recordsSynced: Int!
  """The status of the integration."""
  status: String!
}

"""How the inventory module is used."""
type AdminInventoryModuleUsage {
  """How many warehouses are active."""
  activeWarehouses: Int!
  """How many stock movements there were."""
  stockMovements: Int!
  """How many inventory transactions there were."""
  transactions: Int!
}

"""How the modules are used."""
type AdminModuleUsage {
  """The finance module."""
  finance: AdminFinanceModuleUsage!
  """The inventory module."""
  inventory: AdminInventoryModuleUsage!
  """The purchase module."""
  purchase: AdminPurchaseModuleUsage!
  """The sales module."""
  sales: AdminSalesModuleUsage!
}

"""Notification counts for the admin."""
type AdminNotifications {
  """How many critical alerts there are."""
  criticalAlerts: Int!
  """How many system messages there are."""
  systemMessages: Int!
  """How many notifications are unread."""
  unreadCount: Int!
}

"""How the purchase module is used."""
type AdminPurchaseModuleUsage {
  """How many purchase orders are active."""
  activeOrders: Int!
  """How many goods receipts are pending."""
  pendingGRN: Int!
  """How many suppliers there are."""
  supplierCount: Int!
}

"""A recent sign in."""
type AdminRecentLogin {
  """The IP address they signed in from."""
  ipAddress: String!
  """When they signed in."""
  loginTime: DateTime!
  "The ID of the user."
  userId: String!
  """The name of the user."""
  userName: String!
}

"""How the sales module is used."""
type AdminSalesModuleUsage {
  """How many invoices are pending."""
  invoicesPending: Int!
  """How many orders were placed today."""
  ordersToday: Int!
  """How many quotes are active."""
  quotesActive: Int!
}

"""Security figures."""
type AdminSecurityMetrics {
  """How many sign in attempts failed."""
  failedLoginAttempts: Int!
  """When the last security scan ran."""
  lastSecurityScan: DateTime!
  """How many security updates are pending."""
  pendingSecurityUpdates: Int!
  """The days until the SSL certificate expires."""
  sslCertificateExpiry: Int!
  """How many suspicious activities were flagged."""
  suspiciousActivities: Int!
}

"""How the system is performing."""
type AdminSystemHealth {
  """The average API response time, in milliseconds."""
  apiResponseTime: Float!
  """The share of reads served from cache, in percent."""
  cacheHitRate: Float!
  """The CPU in use, in percent."""
  cpuUsage: Float!
  """The size of the database."""
  databaseSize: Float!
  """The disk in use, in percent."""
  diskUsage: Float!
  """The share of requests that failed, in percent."""
  errorRate: Float!
  """The memory in use, in percent."""
  memoryUsage: Float!
}

"""Headline system figures."""
type AdminSystemOverview {
  """How many users are active."""
  activeUsers: Int!
  """When the last backup ran."""
  lastBackup: DateTime
  """How revenue is moving, in percent."""
  revenueTrend: Float
  """The share of time the system was up, in percent."""
  systemUptime: Float!
  """How many orders there are."""
  totalOrders: Int!
  """How many organizations there are."""
  totalOrganizations: Int!
  """How many products there are."""
  totalProducts: Int!
  """The total revenue."""
  totalRevenue: Float!
  """How many users there are."""
  totalUsers: Int!
}

"""How active users are."""
type AdminUserActivity {
  """How many users were active today."""
  dailyActiveUsers: Int!
  """How many users were active this month."""
  monthlyActiveUsers: Int!
  """The most recent sign ins."""
  recentLogins: [AdminRecentLogin!]!
  """How many users were active this week."""
  weeklyActiveUsers: Int!
}

"""Open invoices that are a given number of days past due."""
type AgingBucket {
  """The age range, for example current, 1-30, 31-60, 61-90 or 90+ days."""
  bucket: String!
  """How many invoices are in the range."""
  count: Int!
  """The amount still owed."""
  value: Float!
}

"""The AI credit balance."""
type AiCreditBalanceInfo {
  """
  Remaining balance in dollars, e.g. "9.84"
  """
  balanceDollars: String!
  """
  Preformatted balance, e.g. "USD 9.84" (matches the Claude console style)
  """
  display: String!
}

"""A payment page for topping up AI credits."""
type AiCreditCheckoutSession {
  """The amount, in cents."""
  amountCents: Int!
  """The label of the top up."""
  label: String!
  """The ID of the checkout session."""
  sessionId: String!
  """The address of the payment page."""
  url: String!
}

"""
One day's AI credit spend, for the burn chart. Days with no calls are returned as zero so the chart is continuous.
"""
type AiCreditDailySpend {
  """Credits charged that day, in cents (4dp precision as a string)."""
  creditsUsed: String!
  """Calendar day, ISO yyyy-mm-dd (UTC)."""
  date: String!
}

"""An amount of AI credit that can be bought."""
type AiCreditTopUpOption {
  """The amount, in cents."""
  amountCents: Int!
  """The label to show."""
  label: String!
}

"""One entry in the AI credit ledger."""
type AiCreditTransactionEntry {
  """Positive = credit added, negative = credit used."""
  amountCents: Int!
  "When the record was created."
  createdAt: DateTime!
  """What the entry was for."""
  description: String
  "The unique ID of this record."
  id: ID!
  """
  'PURCHASE' | 'USAGE' | 'BONUS' | 'REFUND' | reservation-hold/settle/release rows.
  """
  type: String!
}

"""
Totals over a period for the wallet page's figures and chart, worked out over the whole period.
"""
type AiCreditUsageSummary {
  """Number of metered calls in the window."""
  callCount: Int!
  """Per-day spend across the window, oldest first, zero-filled."""
  daily: [AiCreditDailySpend!]!
  """Feature that spent the most in the window; null if no usage."""
  topFeature: String
  """Credits the top feature used, in cents (4dp string)."""
  topFeatureCreditsUsed: String
  """Total credits charged in the window, in cents (4dp string)."""
  totalCreditsUsed: String!
  """Days covered by this window."""
  windowDays: Int!
}

"""The organization's AI credit balance."""
type AiCreditWalletBalance {
  """Remaining balance in integer cents."""
  balanceCents: Int!
  """Remaining balance in dollars, e.g. "9.84"."""
  balanceDollars: String!
}

"""One AI call and what it used."""
type AiUsageLogEntry {
  """Raw provider cost in cents (4dp precision as a string), before margin."""
  costCents: String!
  "When the record was created."
  createdAt: DateTime!
  """
  Amount actually charged in cents (4dp precision as a string), cost × margin.
  """
  creditsUsed: String!
  """
  Ready-to-render charge, e.g. "USD 0.12" or "< USD 0.01" for a sub-cent call. Formatted here because platform billing is USD by design and the console must hold no money literal (static-literal guard).
  """
  creditsUsedDisplay: String!
  """The feature that made the call."""
  feature: String
  "The unique ID of this record."
  id: ID!
  """How many input tokens were used."""
  inputTokens: Int!
  """The model used."""
  model: String!
  """How many output tokens were used."""
  outputTokens: Int!
}

"""
Allocates the unallocated cash of an on-account payment to open invoices.
"""
input AllocatePaymentInput {
  """The invoices to allocate to and the amount for each."""
  allocations: [PaymentAllocationInput!]!
  """
  The version of the payment you last read. The change is refused if someone else changed it since.
  """
  expectedVersion: Int
  """The ID of the on-account payment to allocate."""
  paymentId: ID!
}

"""
PENDING = manual instruction saved pre-confirmation; RESERVED = backed by an active reservation; BACKORDER = visible unfulfilled remainder; RELEASED = reservation released (order cancelled/reallocated/expired, OR — — fully shipped).
"""
enum AllocationReservationStatus {
  """The stock is not on hand; the quantity is waiting for supply."""
  BACKORDER
  """The allocation is waiting to be reserved."""
  PENDING
  """The reservation was given back to available stock."""
  RELEASED
  """The stock is held for the order."""
  RESERVED
}

"""
How an allocation row was chosen: engine (AUTO) or human split (MANUAL).
"""
enum AllocationSource {
  """The allocation engine chose the stock."""
  AUTO
  """A person split the allocation by hand."""
  MANUAL
}

"""One warehouse's share of a sales order line."""
input AllocationSplitInput {
  """The quantity from this warehouse, in the order line's unit."""
  quantity: Float!
  """The ID of the warehouse to take the quantity from."""
  warehouseId: ID!
}

"""A warehouse an order line is allocated from."""
type AllocationWarehouseRef {
  """The warehouse code."""
  code: String!
  "The unique ID of this record."
  id: ID!
  """The warehouse name."""
  name: String!
}

"""Analytics time period options"""
enum AnalyticsPeriod {
  """The last six months."""
  LAST_6_MONTHS
  """The last seven days."""
  LAST_7_DAYS
  """The last 30 days."""
  LAST_30_DAYS
  """The last 90 days."""
  LAST_90_DAYS
  """The previous calendar month."""
  LAST_MONTH
  """The previous calendar year."""
  LAST_YEAR
  """The current calendar month so far."""
  THIS_MONTH
  """The current quarter so far."""
  THIS_QUARTER
  """The current calendar year so far."""
  THIS_YEAR
  """Today."""
  TODAY
  """Yesterday."""
  YESTERDAY
}

"""A date range for analytics, with an optional visibility scope."""
input AnalyticsRangeInput {
  """Start of the date range."""
  from: DateTime!
  """
  Which records to include: MINE, TEAM or ALL. The server limits it by role: sales reps always get MINE, admins default to ALL, and other staff default to TEAM and cannot go beyond it.
  """
  scope: AnalyticsScope
  """End of the date range."""
  to: DateTime!
}

"""Visibility scope for analytics v2 queries (MINE / TEAM / ALL)"""
enum AnalyticsScope {
  """Every record in the organization."""
  ALL
  """Only the caller's own records."""
  MINE
  """The caller's records and those of the people who report to them."""
  TEAM
}

"""An API key. The full key is never shown again after it is created."""
type ApiKeyResult {
  """The IP addresses the key may be used from. Empty means any."""
  allowedIps: [String!]
  "When the record was created."
  createdAt: DateTime!
  """When the key stops working."""
  expiresAt: DateTime
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """Full key — only returned on creation"""
  key: String
  """The first characters of the key, to identify it."""
  keyPrefix: String!
  """When the key was last used."""
  lastUsedAt: DateTime
  """The key with most characters hidden."""
  maskedKey: String
  """The name of the key."""
  name: String!
  """How many requests the key may make per period."""
  rateLimit: Int!
  """When the key was revoked."""
  revokedAt: DateTime
  """What the key may do."""
  scope: ApiKeyScope!
  """How many times the key was used."""
  usageCount: Int!
}

"""Scope of API key access"""
enum ApiKeyScope {
  """The key can read data but cannot change it."""
  READ_ONLY
  """The key can read and change data."""
  READ_WRITE
}

"""How the API is performing."""
type ApiMetrics {
  """The average response time, in milliseconds."""
  averageResponseTime: Float!
  """How many requests failed."""
  errorCount: Int!
  """How many requests were made."""
  totalRequests: Int!
}

"""A variant left in abandoned carts, grouped across customers."""
type AppActivityAbandonedProduct {
  """How many different customers have it in an abandoned cart."""
  customers: Int!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The value of those cart lines, in the organization's base currency."""
  value: Float!
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
}

"""Counts that suggest who to follow up with."""
type AppActivityActions {
  """
  How many customers have items in a buying list that they have not ordered.
  """
  buyingListNotOrderedCustomers: Int!
  """How many hours a cart sits before it counts as idle."""
  idleCartAfterHours: Int!
  """How many customers have an idle cart."""
  idleCartCustomers: Int!
  """The value of idle carts, in the organization's base currency."""
  idleCartValue: Float!
  """How many customers had a search that returned nothing."""
  noResultSearchCustomers: Int!
  """How many searches returned nothing."""
  noResultSearches: Int!
  """The share of searches that returned nothing, in percent."""
  noResultSearchesPct: Float!
  """How many searches there were."""
  totalSearches: Int!
  """How many products were viewed and not ordered."""
  viewedNotOrderedProducts: Int!
}

"""How customers use the buyer app and portal."""
type AppActivityAnalytics {
  """Variants left in abandoned carts, most value first."""
  abandonedProducts: [AppActivityAbandonedProduct!]!
  """Counts that suggest who to follow up with."""
  actions: AppActivityActions!
  """When the figures were worked out."""
  asOf: DateTime!
  """
  The ISO 4217 code of every money value here: the organization's base currency.
  """
  baseCurrency: String!
  """Customers and their activity."""
  customers: AppActivityCustomers!
  """App use by day."""
  dailyUse: AppActivityDailyUse!
  """Customers worth following up with."""
  followUps: AppActivityFollowUps!
  """The steps from opening the app to placing an order."""
  funnel: [AppActivityFunnelStepRow!]!
  """The headline figures."""
  kpis: AppActivityKpis!
  """How many days the figures cover."""
  periodDays: Int!
  """Which platforms customers use."""
  platforms: AppActivityPlatforms!
  """How products perform."""
  products: AppActivityProducts!
  """Where the activity data comes from."""
  source: AppActivitySource!
  """Stock worth pushing to customers."""
  stockToPush: AppActivityStockToPush!
}

"""One line of a customer's cart."""
type AppActivityCartLine {
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The quantity."""
  quantity: Float!
  """The value of the line."""
  value: Float!
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
}

"""A customer's cart."""
type AppActivityCartSummary {
  """True when the cart has sat untouched past the idle limit."""
  isIdle: Boolean!
  """How many items the cart has."""
  itemCount: Int!
  """The lines of the cart."""
  lines: [AppActivityCartLine!]!
  """The cart total."""
  total: Float!
  "When the record was last changed."
  updatedAt: DateTime
}

"""How many customers fall in each filter."""
type AppActivityCustomerCounts {
  """All customers."""
  all: Int!
  """Customers on Android."""
  android: Int!
  """Customers going quiet."""
  goingQuiet: Int!
  """Customers on iOS."""
  ios: Int!
  """Very active customers."""
  veryActive: Int!
  """Customers on the web."""
  web: Int!
}

"""One customer's activity in the period."""
type AppActivityCustomerDetail {
  """How many days the customer was active."""
  activeDays: Int!
  """The app version the customer uses."""
  appVersion: String
  """The base currency of the money values."""
  baseCurrency: String!
  """Buying list items not ordered."""
  buyingListNotOrdered: [AppActivityProductEvent!]!
  """The customer's cart now."""
  cart: AppActivityCartSummary!
  """How many times the customer added to the cart."""
  cartAdds: Int!
  """When the customer was last active."""
  lastActiveAt: DateTime
  """When a search last returned nothing."""
  lastNoResultSearchAt: DateTime
  """The name of the customer."""
  name: String!
  """How many searches returned nothing."""
  noResultSearches: Int!
  """The value of those orders."""
  orderValue: Float!
  """How many orders the customer placed."""
  orders: Int!
  "The ID of the partner."
  partnerId: ID!
  """How many days the figures cover."""
  periodDays: Int!
  """The platform the customer uses most."""
  platform: AppActivityPlatform
  """The customer's recent orders."""
  recentOrders: [AppActivityOrderRef!]!
  """Products removed from the cart."""
  removedFromCart: [AppActivityProductEvent!]!
  """How many items the customer removed from the cart."""
  removedItems: Int!
  """How many searches the customer made."""
  searches: Int!
  """Whether the customer is more active, steady or going quiet."""
  trend: AppActivityTrend!
  """Products viewed and not ordered."""
  viewedNotOrdered: [AppActivityProductEvent!]!
  """How many product views."""
  views: Int!
}

"""
Which customers to list: ALL, VERY_ACTIVE, GOING_QUIET, or those on ANDROID, IOS or WEB.
"""
enum AppActivityCustomerFilter {
  """Every customer."""
  ALL
  """Customers who use the Android app."""
  ANDROID
  """Customers whose activity is dropping."""
  GOING_QUIET
  """Customers who use the iOS app."""
  IOS
  """Customers with a high level of recent activity."""
  VERY_ACTIVE
  """Customers who use the web portal."""
  WEB
}

"""A customer, briefly."""
type AppActivityCustomerRef {
  """How many days the customer was active."""
  activeDays: Int!
  """The name of the customer."""
  name: String!
  "The ID of the partner."
  partnerId: ID!
  """The platform the customer uses most."""
  platform: AppActivityPlatform
}

"""One customer row in the activity list."""
type AppActivityCustomerRow {
  """How many days the customer was active."""
  activeDays: Int!
  """The app version the customer uses."""
  appVersion: String
  """How many times the customer added to the cart."""
  cartAdds: Int!
  """When the customer was last active."""
  lastActiveAt: DateTime
  """The name of the customer."""
  name: String!
  """How many orders the customer placed."""
  orders: Int!
  "The ID of the partner."
  partnerId: ID!
  """How many days the figures cover."""
  periodDays: Int!
  """The platform the customer uses most."""
  platform: AppActivityPlatform
  """Whether the customer is more active, steady or going quiet."""
  trend: AppActivityTrend!
  """How many product views."""
  views: Int!
}

"""Customers and their activity."""
type AppActivityCustomers {
  """How many customers fall in each filter."""
  counts: AppActivityCustomerCounts!
  """The filter applied."""
  filter: AppActivityCustomerFilter!
  """The customers."""
  rows: [AppActivityCustomerRow!]!
  """
  How many customers match the filter. The rows are the first part of them.
  """
  total: Int!
}

"""App use over time."""
type AppActivityDailyUse {
  """The buckets."""
  rows: [AppActivityDailyUseRow!]!
  """
  The size of each bucket: day, week or month, from the length of the period.
  """
  unit: String!
}

"""One bucket of app use: orders and customers who opened the app."""
type AppActivityDailyUseRow {
  """How many different customers had any app or portal activity."""
  activeCustomers: Int!
  """
  The bucket, in the organization's time zone, as YYYY-MM-DD, IYYY-IW or YYYY-MM.
  """
  bucket: String!
  """How many committed orders buyers placed."""
  orders: Int!
}

"""What to drill into."""
input AppActivityDrilldownInput {
  """Only rows at this funnel step."""
  funnelStep: AppActivityFunnelStep
  "Maximum number of records to return."
  limit: Int
  """The figure to list the rows behind."""
  metric: AppActivityDrilldownMetric!
  "Number of records to skip before the first one returned."
  offset: Int
  "The ID of the partner."
  partnerId: ID
  """Only rows on this platform."""
  platform: AppActivityPlatform
  """Only rows in this platform group."""
  platformGroup: AppActivityPlatformGroup
  "The ID of the product."
  productId: ID
  "The ID of the product variant."
  variantId: ID
}

"""
The figure whose rows to list. Each value is one number drawer of the report.
"""
enum AppActivityDrilldownMetric {
  """Customers who were active in the period."""
  ACTIVE_CUSTOMERS
  """Orders placed through the app."""
  APP_ORDERS
  """Customers with a product on a buying list who have not ordered it."""
  BUYING_LIST_NOT_ORDERED
  """Add-to-cart events."""
  CART_ADDS
  """Add-to-cart events by one customer."""
  CUSTOMER_CART_ADDS
  """Orders placed by one customer."""
  CUSTOMER_ORDERS
  """Product views by one customer."""
  CUSTOMER_VIEWS
  """Customers who left the buying funnel at a step."""
  FUNNEL_STEP_DROPOFF
  """Carts that were filled and then left."""
  IDLE_CARTS
  """Searches that returned no results."""
  NO_RESULT_SEARCHES
  """Customers on a platform."""
  PLATFORM_CUSTOMERS
  """Customers who added a product to the cart."""
  PRODUCT_ADDERS
  """Customers with a product on a buying list."""
  PRODUCT_BUYING_LIST_CUSTOMERS
  """Orders that include a product."""
  PRODUCT_ORDERS
  """Customers who removed a product from the cart."""
  PRODUCT_REMOVERS
  """Customers who viewed a product."""
  PRODUCT_VIEWERS
  """Views of a product."""
  PRODUCT_VIEWS
}

"""A page of the rows behind a figure."""
type AppActivityDrilldownPage {
  """The base currency of the money values."""
  baseCurrency: String!
  """True when there are more rows."""
  hasMore: Boolean!
  """The figure the rows are behind."""
  metric: AppActivityDrilldownMetric!
  """How many rows were skipped."""
  offset: Int!
  """The rows."""
  rows: [AppActivityDrilldownRow!]!
  """How many rows there are in all."""
  total: Int!
}

"""One row behind a figure."""
type AppActivityDrilldownRow {
  """The main date of the row."""
  at: DateTime
  """
  The main count of the row, such as views, adds, active days or searches.
  """
  count: Float!
  """The name of the customer."""
  customerName: String
  """For buying lists, whether it was ordered since it was added."""
  flag: Boolean
  """
  The platform, app version or buying list name, depending on the figure.
  """
  label: String
  """The ID of the order."""
  orderId: ID
  """The number of the order."""
  orderNumber: String
  "The ID of the partner."
  partnerId: ID
  "The ID of the product."
  productId: ID
  """The name of the product."""
  productName: String
  """A second date where the row has one."""
  secondaryAt: DateTime
  """A second count where the row has one."""
  secondaryCount: Float
  """Money in the base currency. Carts and orders only."""
  value: Float
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
}

"""
Why a customer is worth following up with: IDLE_CART, VIEWED_NOT_ORDERED, BUYING_LIST_NOT_ORDERED or NO_SEARCH_RESULTS.
"""
enum AppActivityFollowUpReason {
  """The customer has a product on a buying list and has not ordered it."""
  BUYING_LIST_NOT_ORDERED
  """The customer left items in the cart."""
  IDLE_CART
  """The customer searched and found nothing."""
  NO_SEARCH_RESULTS
  """The customer viewed a product and did not order it."""
  VIEWED_NOT_ORDERED
}

"""One customer worth following up with, and why."""
type AppActivityFollowUpRow {
  """For an idle cart, how many items it holds."""
  cartItems: Int
  """
  For viewed, the view count. For no search results, the number of empty searches.
  """
  count: Int
  """For an idle cart, the whole days since it was last touched."""
  idleDays: Int
  """When the customer was last active."""
  lastActiveAt: DateTime
  """The name of the customer."""
  name: String!
  "The ID of the partner."
  partnerId: ID!
  """The platform the customer uses most."""
  platform: AppActivityPlatform
  """The product the reason is about, for viewed and buying list reasons."""
  product: AppActivityProductRef
  """Why the customer is worth following up with."""
  reason: AppActivityFollowUpReason!
  """
  For an idle cart, its value in the base currency. Empty for reasons without money.
  """
  value: Float
}

"""Customers worth following up with."""
type AppActivityFollowUps {
  """The customers."""
  rows: [AppActivityFollowUpRow!]!
  """How many there are in all."""
  total: Int!
}

"""
A step from opening the app to placing an order: OPENED, SEARCHED, VIEWED, ADDED_TO_CART, STARTED_CHECKOUT or PLACED_ORDER.
"""
enum AppActivityFunnelStep {
  """Added a product to the cart."""
  ADDED_TO_CART
  """Opened the app."""
  OPENED
  """Placed an order."""
  PLACED_ORDER
  """Searched the catalog."""
  SEARCHED
  """Started checkout."""
  STARTED_CHECKOUT
  """Viewed a product."""
  VIEWED
}

"""One step of the funnel from opening the app to placing an order."""
type AppActivityFunnelStepRow {
  """True when this is the step where the most customers drop off."""
  biggestDrop: Boolean!
  """How many customers reached the step."""
  customers: Int!
  """How many customers were lost at this step."""
  dropOff: Int!
  """
  How many out of every hundred customers who opened the app reached the step.
  """
  perHundred: Int!
  """The step."""
  step: AppActivityFunnelStep!
}

"""Whether product figures are grouped by PRODUCT or by VARIANT."""
enum AppActivityGroupBy {
  """One row per product."""
  PRODUCT
  """One row per product variant."""
  VARIANT
}

"""A product guests opened."""
type AppActivityGuestProduct {
  """How many different guest browsers opened the product page."""
  guests: Int!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
}

"""Visitors who browse without signing in."""
type AppActivityGuests {
  """How many were in the mobile app."""
  app: Int!
  """
  False when the reader can only see their own customers, since guests belong to nobody.
  """
  available: Boolean!
  """
  True when the organization lets guests browse the portal. When false the tab is hidden.
  """
  guestBrowsing: Boolean!
  """How many of the visitors later signed in as a customer."""
  loggedIn: Int!
  """How many days the figures cover."""
  periodDays: Int!
  """How many times guests opened a product page."""
  productViews: Int!
  """The products guests opened the most."""
  topProducts: [AppActivityGuestProduct!]!
  """How many different guest browsers there were."""
  visitors: Int!
  """How many were on the web portal."""
  web: Int!
}

"""The headline figures, each with the previous period for comparison."""
type AppActivityKpis {
  """How many customers were active."""
  activeCustomers: Int!
  """The same for the previous period."""
  activeCustomersPrevious: Int!
  """How many committed orders buyers placed, in the app and portal."""
  appOrders: Int!
  """The same for the previous period."""
  appOrdersPrevious: Int!
  """How many times items were added to carts."""
  cartAdds: Int!
  """The same for the previous period."""
  cartAddsPrevious: Int!
  """The most active customer."""
  mostActive: AppActivityCustomerRef
  """The product added to carts the most."""
  mostAdded: AppActivityProductRow
  """The product ordered the most."""
  mostOrdered: AppActivityProductRow
  """The most viewed product."""
  mostViewed: AppActivityProductRow
  """The most viewed item's share of all views, in percent."""
  mostViewedSharePct: Float!
  """How many active customers placed at least one order."""
  orderingCustomers: Int!
  """How many product views there were."""
  productViews: Int!
  """The same for the previous period."""
  productViewsPrevious: Int!
}

"""Options for the activity report."""
input AppActivityOptionsInput {
  """Which customers to list."""
  customerFilter: AppActivityCustomerFilter
  """Whether to group product figures by product or by variant."""
  groupBy: AppActivityGroupBy
}

"""An order, briefly."""
type AppActivityOrderRef {
  """The order total, in the organization's base currency."""
  baseTotal: Float!
  """The date of the order."""
  orderDate: DateTime!
  """The ID of the order."""
  orderId: ID!
  """The number of the order."""
  orderNumber: String!
  """The status of the order."""
  status: String!
}

"""The platform a customer uses: ANDROID, IOS or WEB."""
enum AppActivityPlatform {
  """The Android app."""
  ANDROID
  """The iOS app."""
  IOS
  """The web portal."""
  WEB
}

"""
Where an active customer shopped in the period: PORTAL_ONLY, APP_ONLY, BOTH, or UNKNOWN for activity with no platform. Each customer is in exactly one group.
"""
enum AppActivityPlatformGroup {
  """Customers who only use the mobile app."""
  APP_ONLY
  """Customers who use both the app and the portal."""
  BOTH
  """Customers who only use the web portal."""
  PORTAL_ONLY
  """Customers whose platform is not known."""
  UNKNOWN
}

"""Customers on one platform."""
type AppActivityPlatformRow {
  """How many customers."""
  customers: Int!
  """The platform."""
  platform: AppActivityPlatform!
  """Their share of all customers, in percent."""
  sharePct: Float!
}

"""Which platforms customers use."""
type AppActivityPlatforms {
  """How many customers were active."""
  activeCustomers: Int!
  """How many app users used Android most, each counted once."""
  appAndroid: Int!
  """How many app users used iOS most, each counted once."""
  appIos: Int!
  """How many used only the mobile app."""
  appOnly: Int!
  """How many used both."""
  both: Int!
  """How many used only the portal."""
  portalOnly: Int!
  """Customers per platform."""
  rows: [AppActivityPlatformRow!]!
  """The most used app version."""
  topAppVersion: String
  """How many customers use it."""
  topAppVersionCustomers: Int!
  """How many had activity with no platform."""
  unknown: Int!
}

"""A product a customer did something with."""
type AppActivityProductEvent {
  """When it last happened."""
  at: DateTime
  """How many times."""
  count: Int!
  """The name of the buying list, for buying list rows."""
  listName: String
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
}

"""A product, briefly."""
type AppActivityProductRef {
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
}

"""One product's activity."""
type AppActivityProductRow {
  """How many customers have it in a buying list now."""
  buyingListCustomers: Int!
  """How many times it was added to a cart."""
  cartAdds: Int!
  """When it was last added to a buying list."""
  lastAddedToList: DateTime
  """Of those, how many ordered it after adding it."""
  orderedSinceAdding: Int!
  """How many committed orders contain it."""
  orders: Int!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """
  How many customers added it, no longer have it in a cart, and have not ordered it.
  """
  removedCustomers: Int!
  """How many units were ordered, in the base unit."""
  units: Float!
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
  """For a product, its viewed variants, most viewed first."""
  variants: [AppActivityProductRow!]
  """How many different customers viewed it."""
  viewers: Int!
  """How many views."""
  views: Int!
}

"""How products perform."""
type AppActivityProducts {
  """Whether the figures are by product or by variant."""
  groupBy: AppActivityGroupBy!
  """The most added to carts."""
  mostAdded: [AppActivityProductRow!]!
  """The most in buying lists."""
  mostInBuyingLists: [AppActivityProductRow!]!
  """The most ordered anywhere."""
  mostOrderedAll: [AppActivityProductRow!]!
  """The most ordered in the app."""
  mostOrderedApp: [AppActivityProductRow!]!
  """The most viewed."""
  mostViewed: [AppActivityProductRow!]!
  """Viewed and not ordered."""
  viewedNotOrdered: [AppActivityProductRow!]!
}

"""Where activity data comes from: ARC itself or FIREBASE."""
enum AppActivitySource {
  """Events recorded by the platform."""
  ARC
  """Events imported from Firebase."""
  FIREBASE
}

"""
Why stock is worth pushing: NOT_SEEN when nobody viewed it, SEEN_NOT_BOUGHT when it was viewed and never ordered.
"""
enum AppActivityStockReason {
  """The product was in stock and no customer looked at it."""
  NOT_SEEN
  """Customers viewed the product and did not buy it."""
  SEEN_NOT_BOUGHT
}

"""One variant worth pushing."""
type AppActivityStockRow {
  """How many committed orders contain it."""
  orders: Int!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """Why it is worth pushing."""
  reason: AppActivityStockReason!
  """The value of the stock on hand, valued as in the dead stock report."""
  stockValue: Float!
  "The ID of the product variant."
  variantId: ID
  """The name of the variant."""
  variantName: String
  """How many different customers viewed it."""
  viewers: Int!
}

"""
Stock worth pushing, counted over every qualifying variant with rows capped per reason.
"""
type AppActivityStockToPush {
  """How many nobody viewed."""
  notSeen: Int!
  """The variants, highest stock value first."""
  rows: [AppActivityStockRow!]!
  """How many were viewed and not ordered."""
  seenNotBought: Int!
  """How many variants qualify."""
  total: Int!
}

"""Whether a customer is MORE_ACTIVE, STEADY or GOING_QUIET."""
enum AppActivityTrend {
  """Activity is dropping."""
  GOING_QUIET
  """Activity is rising."""
  MORE_ACTIVE
  """Activity is flat."""
  STEADY
}

"""Appearance settings."""
input AppearanceSettingsInput {
  """The accent colour."""
  accentColor: String
  """The colour of the background wave."""
  backgroundWaveColor: String
  """How rounded corners are."""
  borderRadius: String
  """True to use a more compact layout."""
  compactMode: Boolean
  """True to use animations."""
  enableAnimations: Boolean
  """The URL of the favicon."""
  faviconUrl: String
  """The font."""
  fontFamily: String
  """The base font size."""
  fontSize: String
  """The URL of the logo."""
  logoUrl: String
  """The main colour."""
  primaryColor: String
  """True to show breadcrumbs."""
  showBreadcrumbs: Boolean
  """True to start with the sidebar collapsed."""
  sidebarCollapsed: Boolean
  """Which side the sidebar is on."""
  sidebarPosition: String
  """The theme."""
  theme: String
}

"""Applies a proposal the copilot made."""
input ApplyProposalInput {
  """
  A unique key. Sending the same key again returns the result of the first apply instead of applying twice.
  """
  idempotencyKey: String!
  """The ID of the proposal."""
  proposalId: ID!
  """The ID of the conversation."""
  sessionId: ID!
}

"""The result of applying a proposal."""
type ApplyProposalResult {
  """The ID of the batch of changes that was made."""
  batchId: String!
  """The ID of the job doing the work, when it runs in the background."""
  jobId: String!
  """
  True when the same request had already been applied and this is its earlier result.
  """
  replayed: Boolean!
  """A report of what was changed."""
  report: JSON
}

"""Approves a previewed product import so it is written."""
input ApproveProductImportInput {
  """The ID of the import."""
  importId: String!
  """Use this mode instead of the one chosen when the import was created."""
  modeOverride: ProductImportMode
}

"""Archive a control. It switches off and stays in the history."""
input ArchiveControlInput {
  """The ID of the control."""
  id: ID!
  """Why the control is archived."""
  reason: String!
}

"""Categories to put under a discount scheme."""
input AssignCategoriesDto {
  """The IDs of the categories."""
  categoryIds: [String!]!
}

"""Customers to put under a discount scheme."""
input AssignCustomersDto {
  """The IDs of the customers."""
  customerIds: [String!]!
}

"""Assigns customers to a sales rep."""
input AssignCustomersToRepInput {
  """The IDs of the customers."""
  customerIds: [ID!]!
  """The ID of the user who receives the customers."""
  repId: ID!
}

"""Gives a permission to a role."""
input AssignPermissionInput {
  """Conditions the permission is limited by."""
  conditions: String
  """The ID of the permission."""
  permissionId: ID!
  "The ID of the role."
  roleId: ID!
}

"""Products to put under a discount scheme."""
input AssignProductsDto {
  """The IDs of the products."""
  productIds: [String!]!
}

"""Grants or denies a permission to one user directly."""
input AssignUserPermissionInput {
  """Conditions the permission is limited by."""
  conditions: String
  """When the permission stops applying."""
  expiresAt: String
  """True to grant the permission, false to deny it."""
  granted: Boolean! = true
  """The ID of the permission."""
  permissionId: ID!
  "The ID of the user."
  userId: ID!
}

"""Puts a user in a role."""
input AssignUserToRoleInput {
  """When the user leaves the role."""
  expiresAt: String
  "The ID of the role."
  roleId: ID!
  "The ID of the user."
  userId: ID!
}

"""A customer that can be assigned to a rep."""
type AssignableCustomerRow {
  """
  The ID of the rep who owns the customer now. Empty when it has no owner yet.
  """
  assignedSalesRepId: ID
  """The name of that rep."""
  assignedSalesRepName: String
  """The customer code."""
  code: String
  "The unique ID of this record."
  id: ID!
  """The name of the customer."""
  name: String!
  """The status of the customer."""
  status: String!
}

"""
Which customers the Users & Teams assignment picker lists, relative to the target rep.
"""
enum AssignableCustomerScope {
  """Every customer."""
  ALL
  """Customers assigned to other reps."""
  OTHER_REPS
  """Customers with no rep."""
  UNASSIGNED
}

"""Which customers to list for assignment, one page at a time."""
input AssignableCustomersInput {
  """The page number."""
  page: Int
  """How many customers per page."""
  pageSize: Int
  """
  The ID of the user the customers would be assigned to. Their existing customers are left out.
  """
  repId: ID!
  """Which customers to list."""
  scope: AssignableCustomerScope
  "Text to search for."
  search: String
}

"""A page of customers that can be assigned."""
type AssignableCustomersPage {
  """True when there are more pages."""
  hasNextPage: Boolean!
  """The customers on this page."""
  items: [AssignableCustomerRow!]!
  """The page number."""
  page: Int!
  """How many customers per page."""
  pageSize: Int!
  """How many customers match in all."""
  totalCount: Int!
}

"""How the variants spread across the values of one attribute."""
type AttributeDistribution {
  """The attribute."""
  attribute: String!
  """Its values, with counts."""
  values: [AttributeValue!]!
}

"""
One attribute filter, for example Color with the values Red and Black. Values within a key are alternatives, and different keys must all match.
"""
input AttributeFilterInput {
  """The attribute key."""
  key: String!
  """The values to match."""
  values: [String!]!
}

"""One value of an attribute and how many variants have it."""
type AttributeValue {
  """How many variants have it."""
  count: Int!
  """The value."""
  value: String!
}

"""One entry in the audit log."""
type AuditLog {
  """What was done."""
  action: String!
  """What changed, as JSON."""
  changes: JSON!
  "When the record was created."
  createdAt: DateTime!
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  """The ID of the record."""
  entityId: String!
  """The kind of record it was done to."""
  entityType: String!
  "The unique ID of this record."
  id: ID!
  """The IP address it came from."""
  ipAddress: String
  "The ID of the organization the record belongs to."
  organizationId: String
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The user who did it."""
  user: AuditLogUser
  """The browser or app it came from."""
  userAgent: String
  "The ID of the user."
  userId: String!
}

"""A user named in an audit log entry."""
type AuditLogUser {
  "Email address."
  email: String
  """The user's first name."""
  firstName: String!
  "The unique ID of this record."
  id: ID!
  """The user's last name."""
  lastName: String!
}

"""
What happened in an authentication event, such as a sign in, a failed sign in, a password reset or a session change.
"""
enum AuthEvent {
  """The account was locked."""
  ACCOUNT_LOCKED
  """The account was unlocked."""
  ACCOUNT_UNLOCKED
  """A trusted device was removed."""
  DEVICE_REMOVED
  """A device was marked as trusted."""
  DEVICE_TRUSTED
  """A sign-in attempt failed."""
  LOGIN_FAILED
  """A sign-in succeeded."""
  LOGIN_SUCCESS
  """The user signed out."""
  LOGOUT
  """The password was changed."""
  PASSWORD_CHANGED
  """A password reset was completed."""
  PASSWORD_RESET_COMPLETED
  """A password reset was requested."""
  PASSWORD_RESET_REQUESTED
  """A session started."""
  SESSION_CREATED
  """A session expired."""
  SESSION_EXPIRED
  """The user signed in through single sign-on."""
  SSO_LOGIN
  """Activity that looked suspicious was detected."""
  SUSPICIOUS_ACTIVITY
  """Two-factor sign-in was turned off."""
  TWO_FACTOR_DISABLED
  """Two-factor sign-in was turned on."""
  TWO_FACTOR_ENABLED
  """A two-factor code was wrong."""
  TWO_FACTOR_FAILED
  """A two-factor code was accepted."""
  TWO_FACTOR_VERIFIED
}

"""One sign in or security event."""
type AuthLogEntry {
  """The browser."""
  browser: String
  "When the record was created."
  createdAt: DateTime!
  """The device."""
  device: String
  """Why it failed, if it did."""
  errorMessage: String
  """The kind of event."""
  event: AuthEvent!
  "The unique ID of this record."
  id: ID!
  """The IP address it came from."""
  ipAddress: String!
  """Where it came from."""
  location: String
  """The operating system."""
  os: String
  """True when the event succeeded."""
  success: Boolean!
  """The browser or app it came from."""
  userAgent: String
}

"""The result of a sign in."""
type AuthResponse {
  """The token to send with requests."""
  accessToken: String
  """How many seconds the access token lasts."""
  expiresIn: Int
  """True when the user must change their password first."""
  mustChangePassword: Boolean
  """The organization the user signed in to."""
  organization: Organization
  "The ID of the organization the record belongs to."
  organizationId: String
  "The ID of the partner."
  partnerId: String
  """The token to get a new access token."""
  refreshToken: String
  """True when a two-factor code is needed to finish signing in."""
  requires2FA: Boolean
  """True when the user must set up two-factor sign in first."""
  requires2FASetup: Boolean
  """The token that identifies the session."""
  sessionToken: String
  """A single-use token for the two-factor step."""
  tempToken: String
  """The kind of token, for example Bearer."""
  tokenType: String
  """The signed-in user."""
  user: User
  "The ID of the user."
  userId: String
  """The kind of user, such as staff or customer."""
  userType: String
}

"""Sign in figures."""
type AuthStats {
  """How many sign in attempts failed."""
  failedLogins: Int!
  """The most recent events."""
  recentActivity: [AuthLogEntry!]!
  """How many sign ins there were."""
  totalLogins: Int!
  """How many different devices were used."""
  uniqueDevices: Int!
  """How many different locations were used."""
  uniqueLocations: Int!
}

"""Asks permission to export data."""
input AuthorizeExportInput {
  """Context for the audit entry, such as a date range or filter summary."""
  entityLabel: String
  """
  The key of the export, one of the known export keys. Never a raw permission string.
  """
  exportKey: String!
}

"""Whether an export may go ahead."""
type AuthorizeExportResult {
  """True when the export is allowed."""
  allowed: Boolean!
  """True when the organization requires sensitive exports to be encrypted."""
  requireEncryption: Boolean!
}

"""The result of setting up tax automatically for an organization."""
type AutoConfigureTaxResult {
  """The ID of the tax group set as the sales default."""
  defaultSalesTaxGroupId: String
  """How many tax groups were created."""
  groupsCreated: Int!
  """How many tax rates were created."""
  ratesCreated: Int!
  """True when the setup finished."""
  success: Boolean!
  """The kind of tax system that was set up."""
  taxSystemType: String!
}

"""Customer figures for the dashboard."""
type B2BCustomerMetrics {
  """The share of customers who stopped buying, in percent."""
  churnRate: Float!
  """The average revenue a customer brings over their lifetime."""
  customerLifetimeValue: Float!
  """The customer satisfaction score."""
  customerSatisfaction: Float!
  """Customers split into segments."""
  customerSegments: [CustomerSegment!]!
  """The share of customers who kept buying, in percent."""
  retentionRate: Float!
}

"""The B2B dashboard."""
type B2BDashboard {
  """Customer figures."""
  customerMetrics: B2BCustomerMetrics!
  """Financial figures."""
  financialMetrics: B2BFinancialMetrics!
  """Stock figures."""
  inventoryMetrics: B2BInventoryMetrics!
  """The headline figures."""
  kpis: B2BKPIs!
  """Order figures."""
  orderMetrics: B2BOrderMetrics!
  """Sales figures."""
  salesMetrics: B2BSalesMetrics!
}

"""Financial figures for the dashboard."""
type B2BFinancialMetrics {
  """The cash flow."""
  cashFlow: Float!
  """How much of each customer's credit limit is in use."""
  creditUtilization: [CreditUtilization!]!
  """What is owed to vendors."""
  payables: Float!
  """The profit as a percent of revenue."""
  profitMargin: Float!
  """What customers owe."""
  receivables: Float!
}

"""Stock figures for the dashboard."""
type B2BInventoryMetrics {
  """How many products are overstocked."""
  overstockCount: Int!
  """The value of the stock."""
  stockValue: Float!
  """How many products ran out of stock."""
  stockoutCount: Int!
  """The items that move fastest."""
  topMovingItems: [TopMovingItem!]!
  """How many times stock turned over."""
  turnoverRate: Float!
}

"""The headline figures of the dashboard."""
type B2BKPIs {
  """The average order value."""
  averageOrderValue: Float!
  """The share of quotes that became orders, in percent."""
  conversionRate: Float!
  """How many customers joined."""
  newCustomers: Int!
  """The growth in orders against the previous period, in percent."""
  orderGrowth: Float!
  """How many customers ordered again."""
  repeatCustomers: Int!
  """The growth in revenue against the previous period, in percent."""
  revenueGrowth: Float!
  """How many orders there were."""
  totalOrders: Int!
  """The total revenue."""
  totalRevenue: Float!
}

"""Order figures for the dashboard."""
type B2BOrderMetrics {
  """The average time to fulfil an order."""
  averageFulfillmentTime: Float!
  """The share of orders delivered on time, in percent."""
  onTimeDeliveryRate: Float!
  """Orders split by status."""
  ordersByStatus: [B2BOrderStatus!]!
  """How many orders wait for approval."""
  pendingApprovals: Int!
  """The share of orders returned, in percent."""
  returnRate: Float!
}

"""Orders in one status."""
type B2BOrderStatus {
  """How many orders."""
  count: Int!
  """The status."""
  status: String!
  """Their value."""
  value: Float!
}

"""Sales figures for the dashboard."""
type B2BSalesMetrics {
  """Sales by day."""
  dailySales: [DailySales!]!
  """Sales split by category."""
  salesByCategory: [SalesByCategory!]!
  """The customers who bought the most."""
  topCustomers: [B2BTopCustomer!]!
  """The products that sold the most."""
  topProducts: [B2BTopProduct!]!
}

"""A customer who bought a lot."""
type B2BTopCustomer {
  "The ID of the customer."
  customerId: String!
  """The name of the customer."""
  customerName: String!
  """The date of the last order."""
  lastOrderDate: String!
  """How many orders the customer placed."""
  orders: Int!
  """The revenue from the customer."""
  revenue: Float!
}

"""A product that sold a lot."""
type B2BTopProduct {
  """The growth against the previous period, in percent."""
  growth: Float!
  "The ID of the product."
  productId: String!
  """The name of the product."""
  productName: String!
  """How many units were sold."""
  quantity: Int!
  """The revenue from the product."""
  revenue: Float!
}

"""The result of retrying the reservation of backordered order lines."""
type BackorderRetryResult {
  """Sales-order ids that received at least one reservation."""
  ordersAffected: [String!]!
  """Number of order lines that received a (partial) reservation."""
  reservedCount: Int!
}

"""Backup settings."""
input BackupSettingsInput {
  """How often to back up."""
  backupFrequency: String
  """Where backups are stored."""
  backupLocation: String
  """The address told about backup results."""
  backupNotificationEmail: String
  """How many days backups are kept."""
  backupRetentionDays: String
  """The time of day to back up."""
  backupTime: String
  """True to back up automatically."""
  enableAutomaticBackup: Boolean
  """True to compress backups."""
  enableBackupCompression: Boolean
  """True to encrypt backups."""
  enableBackupEncryption: Boolean
}

"""
A bank account the organization receives money into or pays from, in one currency.
"""
type BankAccount {
  """The name the account is known by in the organization."""
  accountName: String!
  """
  The account number, masked. Use revealBankAccountSecrets for the full number.
  """
  accountNumber: String!
  """The kind of account, for example CURRENT or SAVINGS."""
  accountType: String!
  """The name of the bank that holds the account."""
  bankName: String!
  """The bank branch or sort code."""
  branchCode: String
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currencyCode: String!
  """
  The running balance in the account's currency. Processed payments move it, and adjustBankAccountBalance corrects it.
  """
  currentBalance: Float!
  """The IBAN, masked. Use revealBankAccountSecrets for the full value."""
  iban: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """Free-text notes about the account."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The SWIFT or BIC code of the bank."""
  swiftCode: String
  "When the record was last changed."
  updatedAt: DateTime!
}

"""Filters for the bank account list."""
input BankAccountFilter {
  """Only accounts of this type."""
  accountType: String
  "ISO 4217 currency code."
  currencyCode: String
  "Whether the record is active."
  isActive: Boolean
  "Text to search for."
  search: String
}

"""
The unmasked account number and IBAN of a bank account. Returned only by revealBankAccountSecrets, which needs permission and is audited.
"""
type BankAccountSecrets {
  """The full account number."""
  accountNumber: String!
  """The full IBAN."""
  iban: String
}

"""The organization's base currency."""
type BaseCurrencyInfo {
  "ISO 4217 currency code."
  currencyCode: String!
  """The ID of the currency."""
  currencyId: String!
  """The name of the currency."""
  currencyName: String!
  """True when the base currency can no longer be changed."""
  isLocked: Boolean!
  """The currency symbol."""
  symbol: String!
}

"""Whether the base currency can still be changed."""
type BaseCurrencyLockStatus {
  """True when it can no longer be changed."""
  isLocked: Boolean!
  """Why it is locked."""
  reason: String
}

"""Books a courier for an order whose goods were already shipped."""
input BookShipmentForShippedGoodsInput {
  """The courier and service to book."""
  delivery: ShipmentBookingInput!
  """The ID of the warehouse the goods leave."""
  originWarehouseId: String
  "The ID of the sales order."
  salesOrderId: ID!
}

"""
An enabled delivery partner staff may book with. It carries no credentials, settings or webhook detail.
"""
type BookableDeliveryPartnerGql {
  """What the partner supports, such as RATES, BOOKING or RETURNS."""
  capabilities: [String!]!
  """The name of the partner."""
  displayName: String!
  """The provider environment."""
  environment: DeliveryEnvironment!
  "The unique ID of this record."
  id: ID!
  """
  API when the system books with the provider, MANUAL for a custom courier.
  """
  kind: String!
  """The partner's logo, or empty to show a monogram."""
  logoUrl: String
  """
  The limits on a pickup window. Empty when the partner takes no pickup time.
  """
  pickupWindowRules: PickupWindowRules
  """The provider key."""
  providerKey: String!
}

"""A filter on a true or false value."""
input BooleanFilter {
  """The value to match."""
  value: Boolean
}

"""A yes or no outcome."""
type BooleanResponse {
  """True when the action succeeded."""
  success: Boolean!
}

"""
What caps how many of one item a box holds: its space (volume at the packing fill %), its weight limit, nothing fits (bigger than the box whichever way it turns, or no size and a flat box), the item ships in its own packaging, or it has neither a size nor a weight and cannot be counted.
"""
enum BoxFitLimit {
  """
  Not one fits: bigger than the box whichever way it turns, or no size and a flat box.
  """
  DOES_NOT_FIT
  """
  The item has neither a size nor a weight (not even from its category or the default item), so nothing limits it and it cannot be counted.
  """
  NO_SIZE_OR_WEIGHT
  """The item ships in its own packaging, never in a box."""
  OWN_PACKAGING
  """The box's space at the packing fill %."""
  SPACE
  """The box's weight limit, less the empty box."""
  WEIGHT
}

"""A brand products are made or sold under."""
type Brand {
  """The brand code."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the brand is."""
  description: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The URL of the brand logo."""
  logoUrl: String
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """The name of the brand."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """How many products the brand has. Only set on the brand list."""
  productCount: Int
  """The products of the brand."""
  products: [Product!]
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The brand's website."""
  websiteUrl: String
}

"""Filters and sorting for the brand list."""
input BrandFilterInput {
  """Only brands created on or after this date."""
  dateFrom: String
  """Only brands created on or before this date."""
  dateTo: String
  "Text to search for."
  search: String
  "Number of records to skip. Send with take to page through results."
  skip: Int = 0
  """The column to sort by. Defaults to name, A to Z."""
  sortBy: BrandSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only brands in this status."""
  status: BrandStatus = ACTIVE
  "Number of records to return."
  take: Int
}

"""A page of brands."""
type BrandListResponse {
  """The brands on this page."""
  brands: [Brand!]!
  """How many brands match the filter in all."""
  total: Int!
}

"""A home section showing a mix of brand logos."""
type BrandPremixSection {
  """The brand logos."""
  brands: [HomeBrandLogoCell!]!
  """The kind of home section."""
  kind: HomeSectionKind!
  """The subtitle of the section."""
  subtitle: String
  """The title of the section."""
  title: String
}

"""
The result of assigning existing products to a brand, or removing them.
"""
type BrandProductAssignmentResult {
  """The brand."""
  brand: Brand!
  """
  How many products had their brand changed to, or cleared from, this brand.
  """
  changedCount: Int!
  """Of those, how many were on a different brand before."""
  reassignedCount: Int!
  """
  How many requested products needed no change: already on the brand, or not found.
  """
  skippedCount: Int!
}

"""A column the brand list can be sorted by."""
enum BrandSortField {
  """When the brand was created."""
  CREATED_AT
  """The brand name."""
  NAME
  """The number of products in the brand."""
  PRODUCT_COUNT
}

"""Filter brands by status"""
enum BrandStatus {
  """Only active brands."""
  ACTIVE
  """Active and inactive brands."""
  ALL
  """Only inactive brands."""
  INACTIVE
}

"""Headline brand figures."""
type BrandSummary {
  """How many are active."""
  activeBrands: Int!
  """How many have products."""
  brandsWithProducts: Int!
  """How many are inactive."""
  inactiveBrands: Int!
  """The most recently added brands."""
  recentBrands: [Brand!]!
  """How many brands there are."""
  totalBrands: Int!
}

"""A category import row that was rejected."""
type BulkCategoryImportError {
  """A machine-readable reason for the rejection."""
  code: String!
  """What was wrong with the row."""
  errors: [String!]!
  """The row number in the file."""
  row: Int!
}

"""A file of categories to import."""
input BulkCategoryImportInput {
  """The content of the file."""
  fileContent: String!
  """The file format."""
  format: ImportFormat!
  """
  True to update categories that already exist instead of rejecting them.
  """
  updateExisting: Boolean! = false
  """True to check the file without saving anything."""
  validateOnly: Boolean! = true
}

"""The outcome of a category import."""
type BulkCategoryImportResult {
  """How many of those created a new category."""
  created: Int!
  """The rejected rows, and why."""
  errors: [BulkCategoryImportError!]!
  """How many rows were rejected."""
  failed: Int!
  """How many rows were saved."""
  success: Int!
  """How many rows the file has."""
  totalRows: Int!
  """How many of those updated an existing category."""
  updated: Int!
}

"""A spreadsheet row that could not be created."""
type BulkCreateProductError {
  """The field that was wrong."""
  field: String
  """What was wrong."""
  message: String!
  """The position of the row in the spreadsheet."""
  rowIndex: Int!
  """The SKU on the row."""
  sku: String!
}

"""
One spreadsheet row of a bulk create. Each row is one product variant with its product data.
"""
input BulkCreateProductRowInput {
  """The name of the base unit of measure."""
  baseUOMName: String
  """The name of the brand."""
  brandName: String
  """The name of the category."""
  categoryName: String
  """The cost of one unit."""
  cost: Float
  """The name of the unit of measure stock is kept in."""
  inventoryUOMName: String
  """The list price. Must be greater than zero."""
  price: Float
  """The name of the product."""
  productName: String!
  """The name of the unit of measure used for purchases."""
  purchaseUOMName: String
  """The sale price."""
  salePrice: Float
  """The name of the unit of measure used for sales."""
  salesUOMName: String
  """The SKU of the variant."""
  sku: String!
  """The opening stock quantity."""
  stockQuantity: Float
  """The name of the unit of measure."""
  uomName: String
  """The name of the variant."""
  variantName: String
}

"""A product variant that was created."""
type BulkCreateProductSuccess {
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The position of the row in the spreadsheet."""
  rowIndex: Int!
  """The SKU of the variant."""
  sku: String!
  "The ID of the product variant."
  variantId: ID!
}

"""The rows of a bulk product create."""
input BulkCreateProductsInput {
  """The spreadsheet rows to create."""
  rows: [BulkCreateProductRowInput!]!
}

"""The outcome of a bulk product create."""
type BulkCreateProductsResult {
  """The rows that were created."""
  created: [BulkCreateProductSuccess!]!
  """How many rows were created."""
  createdCount: Int!
  """The rows that failed, and why."""
  errors: [BulkCreateProductError!]!
  """How many rows failed."""
  failedCount: Int!
  """True when every row was created."""
  success: Boolean!
}

"""An import file and its options."""
input BulkImportInput {
  """Optional: a customer to associate the imported rows with."""
  customerId: String
  """The import file, base64-encoded."""
  fileContent: String!
  """File format: CSV or EXCEL."""
  format: ImportFormat!
  """Optional: a supplier to associate the imported rows with."""
  supplierId: String
  """
  When true, rows that match an existing record update it. Defaults to false.
  """
  updateExisting: Boolean = false
  """
  When true (the default) the file is only checked and nothing is created or changed.
  """
  validateOnly: Boolean = true
}

"""An invoice import file and its options."""
input BulkImportInvoicesInput {
  """
  The ID of the customer to assign imported invoices to. An error is reported if no such customer exists.
  """
  customerId: String
  """The import file, base64-encoded."""
  fileContent: String!
  """File format: CSV or EXCEL."""
  format: InvoiceImportFormat!
  """The type of invoice being imported. Defaults to SALES_INVOICE."""
  invoiceType: InvoiceImportType! = SALES_INVOICE
  """
  When true, rows that match an existing invoice update it. Defaults to false.
  """
  updateExisting: Boolean! = false
  """
  When true (the default) the file is only checked and nothing is created or changed.
  """
  validateOnly: Boolean! = true
}

"""A CSV file to preview as a generic product import."""
input BulkImportProductsGenericInput {
  """The CSV file content, Base64 encoded."""
  file: String!
  """
  How the columns are mapped: a known supplier layout, or detected from the headers.
  """
  mappingProfile: GenericImportMappingProfile!
}

"""The outcome of a bulk invoice import."""
type BulkImportResult {
  """The rejected rows, one entry each."""
  errors: [ImportError!]!
  """How many rows were rejected."""
  failed: Int!
  """How many invoices were imported."""
  success: Int!
}

"""The outcome of approving or rejecting several pending customers."""
type BulkPendingActionResult {
  """An ID that ties together the audit log entries written for this batch."""
  batchId: String!
  """How many were skipped or failed."""
  failed: Int!
  """The outcome for each customer."""
  results: [BulkPendingItemResult!]!
  """How many were handled."""
  succeeded: Int!
  """How many customers were in the batch."""
  total: Int!
}

"""The outcome for one pending customer in a bulk action."""
type BulkPendingItemResult {
  """A machine-readable reason when it was not."""
  code: String
  "The unique ID of this record."
  id: ID!
  """
  Why it was skipped or failed, for example it was already handled by another admin.
  """
  message: String
  """
  The name of the customer. Empty when the ID was not found in the organization's pending queue.
  """
  name: String
  """True when the customer was handled."""
  success: Boolean!
}

"""The result of moving customers to another rep."""
type BulkReassignResult {
  """How many customers were moved."""
  count: Int!
}

"""Changes to several discount schemes at once."""
input BulkUpdateDiscountSchemeDto {
  """The changes, one per scheme."""
  updates: [BulkUpdateItemDto!]!
}

"""A change to one discount scheme."""
input BulkUpdateItemDto {
  """The changes."""
  data: UpdateDiscountSchemeDto!
  """The ID of the scheme."""
  id: String!
}

"""Changes several settings at once."""
input BulkUpdateSettingsInput {
  """The changes."""
  settings: [UpdateTenantSettingInput!]!
}

"""
One interaction event from a buyer client. The organization, user and buyer account come from the sign-in, and there is no free text.
"""
input BuyerActivityEventInput {
  "ISO 4217 currency code."
  currency: String
  """The name of the event."""
  name: String!
  """
  When it happened on the device. Refused if far in the past or in the future.
  """
  occurredAt: DateTime!
  "The ID of the product."
  productId: String
  """
  An amount in the event's currency, for display and never in the base currency.
  """
  value: Float
  "The ID of the product variant."
  variantId: String
}

"""Whether a self-registering buyer is a business or an individual."""
enum BuyerBusinessType {
  """The buyer is a registered business."""
  BUSINESS
  """The buyer is an individual."""
  INDIVIDUAL
}

"""
Whether a buyer account exists for an email address. If it does, the app goes to the one-time code sign in, otherwise to sign up.
"""
type BuyerExistsResponse {
  """True when a customer with this email already exists in this tenant."""
  exists: Boolean!
  """
  The tenant's PortalConfiguration.allowSelfRegistration toggle (default true). When exists=false: true → route to the Sign Up screen; false → show a 'registration disabled' alert and do NOT route to Sign Up.
  """
  selfRegistrationEnabled: Boolean!
}

"""ADD or REMOVE — which half of a group's write this result is."""
enum BuyingListWriteOp {
  """Put a product on the list."""
  ADD
  """Take a product off the list."""
  REMOVE
}

"""What to work a discount out for."""
input CalculateDiscountDto {
  """The amount before discount."""
  baseAmount: Float!
  "The ID of the category."
  categoryId: String
  """The ID of the currency of the amount."""
  currencyId: String
  "The ID of the partner."
  partnerId: String
  "The ID of the product."
  productId: String
  """The quantity."""
  quantity: Int!
  """The ID of the region of the sale."""
  regionId: String
  "The ID of the product variant."
  variantId: String
}

"""The discount worked out on an amount."""
type CalculateDiscountResult {
  """The schemes that were applied."""
  appliedSchemes: [String!]!
  """Every discount that was considered."""
  availableDiscounts: [DiscountDetail!]!
  """The discount."""
  discountAmount: Float!
  """The discount as a percent of the original amount."""
  discountPercentage: Float!
  """The amount after discount."""
  finalPrice: Float!
  """The amount before discount."""
  originalPrice: Float!
}

"""The price worked out for a quantity, after any tier applies."""
type CalculatedPrice {
  """The discount the tier gives."""
  discount: Float!
  """True when a price could be worked out."""
  isValid: Boolean!
  """The price before the tier."""
  originalPrice: Float!
  """The price after the tier."""
  price: Float!
  """The name of the tier that applied."""
  tierName: String!
}

"""
Server-side re-priced bill for the current cart. Every line is re-resolved through LinePricingService at read time — a line with no price in the requested currency throws NO_PRICE_IN_CURRENCY rather than falling back to the stored price (step 4).
"""
type CartBill {
  """When the bill was worked out."""
  asOf: DateTime!
  """
  Post-waiver delivery fee actually charged (0 when waived). Null only when `deliverySelectionRequired` — the store prices delivery live and no option is chosen yet.
  """
  deliveryFee: Float
  """True when subtotal >= freeDeliveryThreshold (exactly-at waives)."""
  deliveryFeeWaived: Boolean!
  """the live delivery option this bill's fee came from."""
  deliveryOptionId: ID
  """
  Box packing: true when the order is too heavy to price delivery live (delivery options code DELIVERY_FREIGHT_QUOTE) — it is placed with no delivery charge (deliveryFee 0) and the store quotes delivery afterwards. Show "Delivery quoted after ordering".
  """
  deliveryQuoteRequired: Boolean!
  """
  true when the store prices delivery live and the buyer has not chosen a delivery option — deliveryFee is null and grandTotal excludes delivery until one is passed as deliveryOptionId.
  """
  deliverySelectionRequired: Boolean!
  """
  Total discount across every line (baseUnitPrice − unitPrice, summed) — the seller-portal Discount row (0 when nothing applies).
  """
  discountAmount: Float!
  """
  What the cart still needs to reach freeDeliveryThreshold, on the basis the waiver is measured on (tax-inclusive lines at their gross); 0 once reached, null when there is no threshold.
  """
  freeDeliveryRemaining: Float
  """
  The store's free-delivery threshold — the flat-fee one, or the live-price one on a store that prices delivery live (null = none).
  """
  freeDeliveryThreshold: Float
  """subtotal + taxAmount + deliveryFee (parity chain)."""
  grandTotal: Float!
  """
  The true GROSS, pre-discount total (Σ list price × qty) — the seller-portal-parity Subtotal row. Do not derive this as subtotal + discountAmount; that re-rounds an already-rounded net figure and can drift by a cent.
  """
  grossSubtotal: Float!
  """How many items the cart has."""
  itemCount: Int!
  """The lines of the bill."""
  lines: [CartBillLine!]!
  """
  NET of discount (the tax base) — computed as round(grossSubtotal) − round(discountAmount), admin-parity (never round an exact net figure directly; see BUG-20260818).
  """
  subtotal: Float!
  """
  Total tax on the bill (includes delivery-fee tax when the fee is charged).
  """
  taxAmount: Float!
}

"""One line of the cart bill."""
type CartBillLine {
  """
  Pre-discount per-unit price from the same LinePricingService resolution (display-only strikethrough reference). Equal to unitPrice when nothing discounts this line.
  """
  baseUnitPrice: Float!
  """The ID of the cart item."""
  cartItemId: ID!
  """
  Σ per-unit discount × quantity for this line, rounded once (repriceLines).
  """
  discountAmount: Float!
  """
  Line discount rate for display, computed server-side from the EXACT discount over the pre-discount line base and snapped to 2dp (12.345 % shows 12.35, 45 % stays 45). Never derive it from the rounded discountAmount (10.30 at 45 % would read 45.05).
  """
  discountPercent: Float
  """The line total."""
  lineTotal: Float!
  """The quantity."""
  quantity: Float!
  """Engine-resolved tax amount for this line (lineTotal × taxRate)."""
  taxAmount: Float!
  """Engine-resolved tax rate percent for this line (LinePricingService)."""
  taxRate: Float!
  """Freshly re-resolved unit price (never the stale stored cart price)."""
  unitPrice: Float!
  "The ID of the product variant."
  variantId: ID!
}

"""The product on a cart item."""
type CartItemProduct {
  "The unique ID of this record."
  id: ID!
  """The URL of the product image."""
  imageUrl: String
  """The name of the product."""
  name: String!
  """The SKU of the variant."""
  sku: String!
}

"""One item in the cart."""
type CartItemType {
  """
  Buyer consent: if this item becomes unavailable, may fulfillment ship a manually-picked substitute instead? Consent + visibility only — carries forward automatically, never re-prompted.
  """
  acceptAlternativeIfUnavailable: Boolean!
  """
  Pre-discount per-unit price from the same LinePricingService resolution (display-only, e.g. a strikethrough list price next to unitPrice). Equal to unitPrice when nothing discounts this line.
  """
  baseUnitPrice: Float!
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """The line total."""
  lineTotal: Float!
  """A note on the line."""
  notes: String
  """The product."""
  product: CartItemProduct!
  """The quantity."""
  quantity: Float!
  """The price of one unit."""
  unitPrice: Float!
  """The unit of measure."""
  uom: CartItemUom!
  """The variant."""
  variant: CartItemVariant!
}

"""
A unit (pack) offered for a cart item, with its minimum, maximum and multiple order quantities.
"""
type CartItemUom {
  """The code of the unit of measure."""
  code: String!
  "The unique ID of this record."
  id: ID!
  """The largest quantity for one line in this unit. Empty means no cap."""
  maxOrderQuantity: Float
  """
  The smallest quantity for one line in this unit, using the stricter of the variant's rule and the pack's own.
  """
  minOrderQuantity: Float
  """The name of the unit of measure."""
  name: String!
  """Quantities step by this."""
  orderMultiple: Float
}

"""The variant on a cart item."""
type CartItemVariant {
  "The unique ID of this record."
  id: ID!
  """The name of the variant."""
  name: String!
  """The SKU of the variant."""
  sku: String!
}

"""The cart's totals."""
type CartSummary {
  """How many items the cart has."""
  itemCount: Int!
  """The cart amount before tax and delivery."""
  subtotal: Float!
}

"""The customer's cart."""
type CartType {
  "The unique ID of this record."
  id: ID!
  """How many items the cart has."""
  itemCount: Int!
  """The items in the cart."""
  items: [CartItemType!]!
  """The name of the cart."""
  name: String!
  """
  Optimistic-concurrency counter — pass back as expectedRevision on the next mutation.
  """
  revision: Int!
  """The cart amount before tax and delivery."""
  subtotal: Float!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""Settled payments for one day, from the last 30 days."""
type CashFlowData {
  """The net movement for the day in the base currency."""
  balance: Float!
  """The day, as an ISO 8601 timestamp."""
  date: String!
  """
  Money in for the day in the organization's base currency. Zero when the day's net movement is negative.
  """
  inflow: Float!
  """
  Money out for the day in the base currency. Zero when the day's net movement is positive.
  """
  outflow: Float!
}

"""
Where a batch of catalog changes stands: APPLIED, PARTIAL when only some changes went through, or ROLLED_BACK.
"""
enum CatalogBatchStatus {
  """All changes in the batch were applied."""
  APPLIED
  """Some changes were applied and some failed."""
  PARTIAL
  """The batch was undone."""
  ROLLED_BACK
}

"""A batch of catalog changes made by the copilot."""
type CatalogBatchType {
  """When the batch was applied, in epoch milliseconds."""
  appliedAt: Float!
  """The records the batch changed."""
  entities: JSON!
  "The unique ID of this record."
  id: ID!
  """The kind of batch."""
  kind: CopilotProposalKind!
  """When the batch was rolled back, in epoch milliseconds."""
  rolledBackAt: Float
  """Where the batch stands."""
  status: CatalogBatchStatus!
  """A summary of the batch."""
  summary: JSON!
}

"""Which batches to list."""
input CatalogBatchesInput {
  """How many batches to return."""
  first: Int = 20
}

"""How the catalog performs."""
type CatalogPerformanceAnalytics {
  """The products whose sales are falling."""
  decliningProducts: [ProductPerf!]!
  """How much revenue the discounts gave away."""
  discountLeakage: LeakageSummary!
  """The gross margin."""
  grossMargin: MarginSummary!
  """Revenue split by brand."""
  revenueByBrand: [MixSlice!]!
  """Revenue split by category."""
  revenueByCategory: [MixSlice!]!
  """The products that sold the most."""
  topProducts: [ProductPerf!]!
}

"""A node in the category tree. A root category is an ordinary category."""
type Category {
  """The child categories."""
  children: [Category!]!
  """How many child categories there are."""
  childrenCount: Int!
  """The category code."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the category holds."""
  description: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """The URL of the category image."""
  imageUrl: String
  "Whether the record is active."
  isActive: Boolean!
  """The depth in the tree, starting at 1 for a root."""
  level: Int!
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """The name of the category."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The parent category."""
  parent: Category
  """The ID of the parent category. Empty for a root."""
  parentId: ID
  """The names from the root down to this category."""
  path: String!
  """How many products are directly in the category."""
  productCount: Int!
  """The products in the category."""
  products: [CategoryProduct!]
  """The position among sibling categories, lowest first."""
  sortOrder: Int!
  """How many products are in the category and all categories below it."""
  totalProductCount: Int
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""A page of child categories."""
type CategoryChildrenConnection {
  """True when there are more after this page."""
  hasNextPage: Boolean!
  """The categories on this page."""
  items: [Category!]!
  """The cursor to pass to get the next page."""
  nextCursor: String
  """How many child categories there are in all."""
  totalCount: Int!
}

"""Per-item delivery defaults (cm / kg); null = not set."""
type CategoryDeliveryDefaultValues {
  """The height, in centimetres."""
  heightCm: Float
  """The length, in centimetres."""
  lengthCm: Float
  """Items ship alone in their own packaging."""
  ownPackaging: Boolean
  """The weight of one item, in kilograms."""
  weightKg: Float
  """The width, in centimetres."""
  widthCm: Float
}

"""
A category's delivery defaults: its own values and what applies to its items (inherited from parents).
"""
type CategoryDeliveryDefaults {
  "The ID of the category."
  categoryId: ID!
  """The name of the category."""
  categoryName: String!
  """
  The defaults in force, including those inherited from a parent category.
  """
  effective: CategoryDeliveryDefaultValues!
  """The nearest parent category a value is inherited from."""
  inheritedFromCategoryName: String
  """The defaults set on the category itself."""
  own: CategoryDeliveryDefaultValues!
}

"""
The category's own delivery defaults. They replace what was saved, and null means inherit.
"""
input CategoryDeliveryDefaultsInput {
  """The height, in centimetres."""
  heightCm: Float
  """The length, in centimetres."""
  lengthCm: Float
  """True when items in the category ship in their own packaging."""
  ownPackaging: Boolean
  """The weight of one item, in kilograms."""
  weightKg: Float
  """The width, in centimetres."""
  widthCm: Float
}

"""A category with its subcategories."""
type CategoryDetail {
  "The unique ID of this record."
  id: ID!
  """The URL of the category image."""
  imageUrl: String
  """The name of the category."""
  name: String!
  """The code of the category."""
  slug: String!
  """The subcategories."""
  subcategories: [CategorySubcategory!]!
}

"""Filters for the category list."""
input CategoryFiltersInput {
  """
  Return plain rows and their counts without parent and child relations, which is faster when they are not needed.
  """
  flat: Boolean
  "Whether the record is active."
  isActive: Boolean
  """Only categories at this depth."""
  level: Int
  """Only the children of this category."""
  parentId: ID
  """Only root categories."""
  rootOnly: Boolean
  "Text to search for."
  search: String
}

"""A home section showing a grid of categories."""
type CategoryGridSection {
  """The categories."""
  categories: [HomeCategoryCell!]!
  """The kind of home section."""
  kind: HomeSectionKind!
  """The title of the section."""
  title: String
}

"""A product in a category."""
type CategoryProduct {
  "The unique ID of this record."
  id: ID!
  """The name of the product."""
  name: String!
  """The SKU of the product."""
  sku: String!
  """The status of the product."""
  status: String
}

"""
The result of adding existing products to a category, or removing them.
"""
type CategoryProductAssignmentResult {
  """The category."""
  category: Category!
  """How many products were newly added or removed."""
  changedCount: Int!
  """
  How many requested products needed no change: already there, not there, or not found.
  """
  skippedCount: Int!
}

"""The profit of one category."""
type CategoryProfit {
  "The ID of the category."
  categoryId: String!
  """The name of the category."""
  categoryName: String!
  """The cost of what was sold."""
  cost: Float!
  """The profit as a percent of revenue."""
  margin: Float!
  """The profit: revenue minus cost."""
  profit: Float!
  """The revenue."""
  revenue: Float!
}

"""Purchases in one category."""
type CategoryPurchase {
  """The name of the category."""
  category: String!
  """The value purchased."""
  value: Float!
}

"""The stock of one category."""
type CategoryStock {
  "The ID of the category."
  categoryId: String!
  """The name of the category."""
  categoryName: String!
  """How many are low on stock."""
  lowStockCount: Int!
  """How many products are in the category."""
  totalProducts: Int!
  """The value of the stock."""
  totalValue: Float!
}

"""A subcategory."""
type CategorySubcategory {
  "The unique ID of this record."
  id: ID!
  """The URL of the subcategory image."""
  imageUrl: String
  """The name of the subcategory."""
  name: String!
  """The code of the subcategory."""
  slug: String!
}

"""Headline category figures."""
type CategorySummary {
  """How many are active."""
  activeCategories: Int!
  """How many hold products."""
  categoriesWithProducts: Int!
  """How many hold none."""
  categoriesWithoutProducts: Int!
  """The category tree."""
  categoryTree: [Category!]!
  """How many have a parent."""
  childCategories: Int!
  """How many are inactive."""
  inactiveCategories: Int!
  """When the figures were worked out."""
  lastUpdated: DateTime!
  """
  The deepest level in the tree, starting at 1 for a root. There is no limit; this only reports what has been built.
  """
  maxDepth: Int!
  """The categories that hold the most products."""
  mostUsedCategories: [Category!]!
  """How many have children."""
  parentCategories: Int!
  """The most recently added categories."""
  recentCategories: [Category!]!
  """How many are roots."""
  rootCategories: Int!
  """How many categories there are."""
  totalCategories: Int!
}

"""How one category's sales are moving."""
type CategoryTrend {
  "The ID of the category."
  categoryId: String!
  """The name of the category."""
  categoryName: String!
  """The growth, in percent."""
  growthRate: Float!
  """The direction: up, down or flat."""
  trend: String!
}

"""
Buyer 'change delivery address': swap the ship-to (and bill-to, mirroring placement) for another ACTIVE address of the same company.
"""
input ChangeMobileOrderAddressInput {
  "The ID of the address."
  addressId: ID!
  """
  The version of the order you last read. The change is refused if it changed since.
  """
  expectedVersion: Int
  """The ID of the order."""
  orderId: ID!
}

"""Changes the payment method of an order that has not been paid."""
input ChangeMobileOrderPaymentMethodInput {
  """
  The version of the order you last read. The change is refused if someone else changed it since.
  """
  expectedVersion: Int
  """The ID of the order."""
  orderId: ID!
  """The payment method to switch the order to."""
  paymentMethod: MobilePaymentMethod!
}

"""Input to change the courier of a sales order."""
input ChangeOrderCourierInput {
  """
  The carrier of that rate (an aggregator can quote several carriers under one service).
  """
  carrierName: String!
  """The ID of the delivery partner of the live rate staff picked."""
  deliveryPartnerConfigId: ID!
  """
  The order version you last read. The change is refused if the order has changed since.
  """
  expectedVersion: Int
  """
  A client-chosen key; repeating a request with the same key does not change the order twice.
  """
  idempotencyKey: String
  """Who bears the courier cost. Only KEEP_CUSTOMER_PRICE is accepted."""
  policy: CourierCostPolicy! = KEEP_CUSTOMER_PRICE
  """
  Why the courier is changed. Required whenever the seller pays any part of the cost.
  """
  reason: String
  "The ID of the sales order."
  salesOrderId: ID!
  """The carrier's code for the service level."""
  serviceLevelCode: String!
}

"""Changes the signed-in user's password."""
input ChangePasswordInput {
  """
  The current password. Optional, because a user set up through a one-time code or single sign on has none to give.
  """
  currentPassword: String
  """The new password."""
  newPassword: String!
}

"""A chat channel that people can join."""
type ChatChannel {
  """The conversation held in the channel."""
  conversation: ChatConversation
  "When the record was created."
  createdAt: DateTime!
  """The ID of the user who created the channel."""
  createdBy: String!
  """The user who created the channel."""
  creator: User
  """What the channel is for."""
  description: String
  "The unique ID of this record."
  id: ID!
  "Whether this is the default."
  isDefault: Boolean!
  """True when only invited people can join."""
  isPrivate: Boolean!
  """How many members the channel has."""
  memberCount: Int
  """The members of the channel."""
  members: [ChatChannelMember!]
  """The name of the channel."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A member of a chat channel."""
type ChatChannelMember {
  """The channel."""
  channel: ChatChannel
  """The ID of the channel."""
  channelId: String!
  "The unique ID of this record."
  id: ID!
  """When the member joined."""
  joinedAt: DateTime!
  """The member's role in the channel."""
  role: String!
  """The member."""
  user: User
  "The ID of the user."
  userId: String!
}

"""A chat conversation: a direct chat, a group or a channel."""
type ChatConversation {
  """The ID of the channel, when it is a channel conversation."""
  channelId: String
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """True when more than two people are in it."""
  isGroup: Boolean!
  """When the last message was sent."""
  lastMessageAt: DateTime!
  """How many messages there are."""
  messageCount: Int
  """The messages."""
  messages: [ChatMessage!]
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The title of the conversation."""
  title: String!
  """The kind of conversation."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user."
  userId: String!
}

"""One message in a chat conversation."""
type ChatMessage {
  """The text of the message."""
  content: String!
  """The ID of the conversation."""
  conversationId: String!
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The role of the sender in the conversation."""
  role: String!
  """The sender."""
  sender: User
  """The ID of the sender."""
  senderId: String
}

"""Checks whether a buyer account exists for an email address."""
input CheckBuyerExistsInput {
  "Email address."
  email: String!
  """ARC org subdomain this white-label build is pinned to."""
  subdomain: String
}

"""
Checks whether a customer account exists for an email address or phone number.
"""
input CheckCustomerExistsInput {
  "Email address."
  email: String!
  """
  Dev/localhost fallback for multi-tenant resolution — the request host (X-Original-Host → Host) always wins, exactly like customerLogin.
  """
  subdomain: String
}

"""
One live delivery option for the buyer's cart and address. Pass `id` back as `deliveryOptionId` on the bill and on placement; the server re-validates it and never trusts a client fee.
"""
type CheckoutDeliveryOption {
  """True on the AUTO option: already chosen, nothing to pick."""
  autoSelected: Boolean!
  """
  How many boxes the delivery ships in ("Ships in N boxes") — only when the store chooses to show it; null otherwise.
  """
  boxCount: Int
  """
  The courier's logo (an image URL or PNG data URI), or null — show the carrier name alone.
  """
  carrierLogoUrl: String
  """
  The courier, or null when the store hides courier names — show `label`.
  """
  carrierName: String
  """ISO-4217 currency of `fee`."""
  currency: String!
  """Latest estimated delivery, when the carrier gives one."""
  estimatedDelivery: DateTime
  """
  Earliest estimated delivery, when the carrier gives one and the store shows estimates.
  """
  estimatedDeliveryFrom: DateTime
  """When the price stops being valid."""
  expiresAt: DateTime!
  """
  What the buyer pays for delivery (the carrier's quoted price as-is, or 0 over the free-delivery threshold), in `currency`. No tax is added on top.
  """
  fee: Float!
  """Opaque option id (expires at `expiresAt`)."""
  id: ID!
  """
  SERVICE: one partner service. SPEED: a named speed (`label` is its name). AUTO: the one price the store picked — show it selected, with no picker.
  """
  kind: DeliveryOptionKind!
  """
  The row title to show: the speed name (SPEED), "Delivery" (AUTO, or when the store hides courier and service — translate by `kind`), else "courier · service" from what is shown.
  """
  label: String!
  """
  The delivery partner the courier is booked through (e.g. an aggregator), or null (also when courier names are hidden).
  """
  partnerName: String
  """The service level, or null when the store hides it."""
  serviceLevelName: String
  """The SPEED option's speed id; null otherwise."""
  speedId: String
}

"""
Delivery choices for checkout. FLAT: no options, the bill carries the fee. LIVE_QUOTE: the buyer must pick one option; `code` NO_DELIVERY_OPTIONS means delivery is unavailable to this address; DELIVERY_FREIGHT_QUOTE means the order is too heavy to price live — it may be placed with no delivery option and the store quotes delivery afterwards.
"""
type CheckoutDeliveryOptions {
  """
  How to render the options: LIST (pick a service), SPEEDS (pick a speed), AUTO (one pre-selected price, no picker — still send its id as deliveryOptionId).
  """
  choiceMode: DeliveryChoiceMode!
  """
  NO_DELIVERY_OPTIONS when live-quote checkout has nothing to offer; DELIVERY_FREIGHT_QUOTE when the order is too heavy to price live (place it without a delivery option — the store quotes delivery afterwards); null otherwise.
  """
  code: String
  """How the delivery fee is worked out: a flat fee or a live quote."""
  mode: DeliveryFeeMode!
  """The delivery options on offer."""
  options: [CheckoutDeliveryOption!]!
  """
  With no options: true when a partner failed for a reason that may clear (timeout, provider outage) — offer Retry rather than a dead end.
  """
  retryable: Boolean!
  """The delivery partners that could not give an option, and why."""
  unavailable: [CheckoutDeliveryUnavailable!]!
}

"""A delivery partner that could not price this delivery, and why."""
type CheckoutDeliveryUnavailable {
  """
  The courier inside an aggregator that refused (staff screens only); null for the whole partner.
  """
  carrierName: String
  """
  Machine-readable reason: QUOTES_NOT_SUPPORTED, COUNTRY_NOT_SERVED, CURRENCY_NOT_SUPPORTED, ADDRESS_INCOMPLETE, NO_PRICE, TIMEOUT, PROVIDER_ERROR, CREDENTIALS_UNREADABLE, CARRIER_REFUSED, NO_PICKUP_ADDRESS, DESTINATION_INCOMPLETE, PARCEL_LIMIT_EXCEEDED.
  """
  code: String
  """
  The partner's name; null when the reason applies to every partner (e.g. an incomplete address).
  """
  partnerName: String
  """
  English fallback text. Clients should translate by `code` when they know it.
  """
  reason: String!
  """Asking again may succeed (a timeout or the provider's own outage)."""
  retryable: Boolean!
}

"""Empties the cart."""
input ClearCartInput {
  """CAS guard: the cart revision this mutation was read against."""
  expectedRevision: Int
  """Client-minted id for replay-safety (same id+payload = no-op success)."""
  operationId: String
}

"""Clicks from one browser."""
type ClickByBrowser {
  """The browser."""
  browser: String!
  """How many clicks."""
  count: Int!
}

"""Clicks from one country."""
type ClickByCountry {
  """How many clicks."""
  count: Int!
  """The country."""
  country: String!
}

"""Clicks on one day."""
type ClickByDate {
  """How many clicks."""
  count: Int!
  """The day."""
  date: String!
}

"""Clicks from one kind of device."""
type ClickByDevice {
  """How many clicks."""
  count: Int!
  """The kind of device."""
  device: String!
}

"""Copies a product."""
input CloneProductInput {
  """
  A unique key per user action. Sending the same key again returns the copy already made instead of a second one.
  """
  idempotencyKey: String!
  """
  The name for the copy. Leave blank to name it automatically after the original.
  """
  name: String
  """The ID of the product to copy."""
  sourceProductId: ID!
  """
  The status of the copy. Defaults to INACTIVE, so a copy that is not yet reviewed is never visible to buyers.
  """
  status: ProductStatus
}

"""Copies a role."""
input CloneRoleInput {
  """What the new role is for."""
  description: String
  """True to copy the permissions."""
  includePermissions: Boolean = true
  """True to copy the users."""
  includeUsers: Boolean = false
  """The name to show for the new role."""
  newRoleDisplayName: String!
  """The name of the new role."""
  newRoleName: String!
  """The ID of the role to copy."""
  sourceRoleId: String!
}

"""
closeQuote input. reason is a tenant-defined label (e.g. PRICE, COMPETITOR, TIMING); competitorName/notes apply to LOST.
"""
input CloseQuoteInput {
  """Who won instead (LOST only) — Quote.competitorName."""
  competitorName: String
  """Free-text detail (LOST only) — Quote.lossNotes."""
  notes: String
  """
  WON or LOST. LOST moves the quote to REJECTED; WON records the win reason on a quote that is already won.
  """
  outcome: QuoteCloseOutcome!
  """The ID of the quote to close."""
  quoteId: ID!
  """Why it closed — Quote.winReason (WON) or Quote.lossReason (LOST)."""
  reason: String!
}

"""A block of content on a page."""
type CmsBlock {
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The kind of block."""
  kind: HomeSectionKind!
  """
  Server-written provenance, e.g. { source: 'ai', model, generationId } for a row the section suggester drafted. Not settable by a client.
  """
  metadata: JSON
  """The position of the block on the page."""
  order: Int!
  "The ID of the organization the record belongs to."
  organizationId: ID!
  """Per-kind payload, as the retired Home CMS editor stored it."""
  payload: JSON!
  """Storefront surface(s) this section renders on (APP and/or PORTAL)."""
  surfaces: [PortalSurface!]!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""How customers who joined in one period behave over time."""
type CohortAnalysis {
  """The period the customers joined."""
  cohort: String!
  """How many customers joined."""
  customersCount: Int!
  """The share still buying in each later period, in percent."""
  retentionRates: [Float!]!
  """The revenue in each period."""
  revenueByPeriod: [Float!]!
}

"""Available collection methods for customer collections"""
enum CollectionMethod {
  """A bank transfer."""
  BANK_TRANSFER
  """Cash."""
  CASH
  """A cheque."""
  CHECK
  """A credit card."""
  CREDIT_CARD
  """A debit card."""
  DEBIT_CARD
  """A debit note."""
  DEBIT_NOTE
  """A digital wallet."""
  DIGITAL_WALLET
  """A direct debit."""
  DIRECT_DEBIT
  """An online payment gateway."""
  ONLINE_GATEWAY
  """Any other method."""
  OTHER
  """A standing instruction to the bank."""
  STANDING_INSTRUCTION
}

"""Cash collected in one bucket of time."""
type CollectionTrendPoint {
  """The bucket, for example a day or month."""
  bucket: String!
  """The cash collected."""
  collected: Float!
}

"""
A commission earned by one person on one order. A hierarchical order has one row per member of the reporting chain.
"""
type Commission {
  """The rate applied, in percent."""
  appliedRate: Float!
  """
  The commission in the organization's base currency. Empty on rows from before base amounts were stored.
  """
  baseCommissionAmount: Float
  """
  The order amount in the organization's base currency. Empty on rows from before base amounts were stored.
  """
  baseOrderAmount: Float
  """The reporting chain saved on the commission when it was created."""
  chain: [CommissionChainEntry!]
  """The commission, in the organization's base currency."""
  commissionAmount: Float!
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String
  """The name of the customer on the order."""
  customerName: String
  """The commission as a percent of the order amount."""
  effectiveRate: Float!
  """
  The order's frozen rate from its currency to the base currency, saved when the commission was created.
  """
  exchangeRate: Float
  "The unique ID of this record."
  id: ID!
  """The order lines the commission is made of."""
  items: [CommissionItem!]
  """The level in the reporting chain. 1 is the assigned rep."""
  level: Int!
  """When the commission was locked."""
  lockedAt: DateTime
  """
  How the commission was worked out, for example HIERARCHICAL for the organization's reporting structure.
  """
  mode: String!
  """The order amount the commission is worked out on."""
  orderAmount: Float!
  """The number of the order."""
  orderNumber: String!
  """When the commission was paid."""
  paidAt: DateTime
  "The ID of the partner."
  partnerId: String!
  """The ID of the payout that settled the commission."""
  payoutId: String
  """The month the commission belongs to."""
  period: String!
  """
  True when the commission was recorded at 0% because no rate is set for the person's role. It is not an earned 0%.
  """
  rateMissing: Boolean!
  """The name of the person who earns the commission."""
  repName: String
  """The role the person had when the commission was created."""
  roleSnapshot: String
  "The ID of the sales order."
  salesOrderId: String!
  """The ID of the rep whose order produced the commission."""
  sourceRepId: String
  """Where the commission stands: PENDING, LOCKED, PAID or REVERSED."""
  status: CommissionStatus!
  "The ID of the user."
  userId: String!
}

"""
What one person earns across every order in the filtered set, split by status. It is added up by the database over the whole set.
"""
type CommissionBeneficiary {
  """
  The chain levels the person earned at, lowest first. Hierarchical rows only.
  """
  levels: [Int!]!
  """The amount locked."""
  locked: Float!
  """The name of the person."""
  name: String!
  """
  How many different orders have a row for the person that is not reversed.
  """
  orders: Int!
  """The amount paid."""
  paid: Float!
  """The amount still pending."""
  pending: Float!
  """The pending and locked amounts for each period."""
  periods: [CommissionBeneficiaryPeriod!]!
  """The person's role."""
  role: String
  """Pending plus locked plus paid. Reversed amounts are left out."""
  total: Float!
  "The ID of the user."
  userId: String!
}

"""
A person's pending and locked commission for one period: what a payout could settle.
"""
type CommissionBeneficiaryPeriod {
  """The amount locked."""
  locked: Float!
  """The amount still pending."""
  pending: Float!
  """The period."""
  period: String!
}

"""
One member of the reporting chain saved on a commission when it was created.
"""
type CommissionChainEntry {
  """The level in the chain."""
  level: Int!
  """The rate the member earns, in percent."""
  rate: Float!
  """
  True when the member's role had no active rate at creation, so the 0% was not configured. Empty on snapshots from before this was recorded.
  """
  rateMissing: Boolean
  """The member's role."""
  role: String
  "The ID of the user."
  userId: String!
  """The member's name."""
  userName: String
}

"""Filters and sorting for the commission list."""
input CommissionFiltersInput {
  """Only commissions of this period."""
  period: String
  """The column to sort by. Defaults to newest first."""
  sortBy: CommissionSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only commissions in this status."""
  status: CommissionStatus
  "The ID of the user."
  userId: String
}

"""
One row of the hierarchical commission setup: a staff user, their manager, their level, and the rate set for their role.
"""
type CommissionHierarchyRow {
  """The user's level, used only for display order."""
  level: Int!
  """The rate set for the user's role, in percent. Empty means none is set."""
  rate: Float
  """True when the rate is in force."""
  rateActive: Boolean!
  """The name of the user's primary manager."""
  reportsToName: String
  """The ID of the user's primary manager."""
  reportsToUserId: String
  """The user's role."""
  role: String
  """The email address of the staff user."""
  userEmail: String
  "The ID of the user."
  userId: String!
  """The name of the staff user."""
  userName: String!
}

"""One order line's share of a commission."""
type CommissionItem {
  """The commission on the line."""
  amount: Float!
  "The unique ID of this record."
  id: ID!
  """The amount of the order line."""
  lineAmount: Float!
  "The ID of the product."
  productId: String!
  """The name of the product."""
  productName: String
  """The rate applied, in percent."""
  rate: Float!
}

"""Headline figures of the commission ledger over the whole filtered set."""
type CommissionLedgerSummary {
  """
  The amount and count in each status, including empty ones, in status order.
  """
  byStatus: [CommissionStatusTotal!]!
  """How many commission rows there are, one per person per order."""
  entries: Int!
  """How many different orders there are."""
  orders: Int!
  """
  How many rows that are not reversed were recorded at 0% because their role has no rate.
  """
  unratedCount: Int!
  """The roles of those rows. Empty means a row had no role."""
  unratedRoles: [String]!
}

"""
One order of the ledger with every commission row it produced, one per member of the chain.
"""
type CommissionOrderGroup {
  """The order's rows, with level 1, the assigned rep, first."""
  commissions: [Commission!]!
  """The number of the order."""
  orderNumber: String!
  "The ID of the sales order."
  salesOrderId: String!
}

"""A payout settling a rep's commissions for a period."""
type CommissionPayout {
  """How many commissions it settles."""
  commissionCount: Int!
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """When it was paid."""
  paidAt: DateTime
  """The period the payout covers."""
  period: String!
  """The payment reference."""
  reference: String
  """The name of the rep."""
  repName: String
  """The status of the payout."""
  status: CommissionStatus!
  """The total paid out."""
  totalAmount: Float!
  "The ID of the user."
  userId: String!
}

"""
The commission rate set for one role. Every chain member with the role earns it.
"""
type CommissionRoleRate {
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The rate, in percent."""
  rate: Float!
  """The role."""
  role: String!
}

"""A column the commission list can be sorted by."""
enum CommissionSortField {
  """The commission amount."""
  COMMISSION_AMOUNT
  """When the commission was created."""
  CREATED_AT
  """The order amount the commission is based on."""
  ORDER_AMOUNT
  """The commission period."""
  PERIOD
}

"""
Where a commission stands: PENDING while the customer has not paid, LOCKED once the order is paid or confirmed, PAID once settled in a payout, REVERSED when the order was cancelled or returned before payout.
"""
enum CommissionStatus {
  """Locked for payout and no longer changes."""
  LOCKED
  """Paid out."""
  PAID
  """Earned and waiting for payout."""
  PENDING
  """Cancelled after the order was reversed."""
  REVERSED
}

"""The amount and count of one status in the ledger summary."""
type CommissionStatusTotal {
  """The total amount."""
  amount: Float!
  """How many commissions."""
  count: Int!
  """The status."""
  status: CommissionStatus!
}

"""A rep's commission figures."""
type CommissionSummary {
  """The rep's commission rate, in percent."""
  defaultRate: Float!
  """Last calendar month's commission, pending plus locked plus paid."""
  lastMonthTotal: Float!
  """The date of the last payout."""
  lastPayoutDate: DateTime
  """The commission earned over all time."""
  lifetimeEarned: Float!
  """The commission earned and not yet paid."""
  lifetimeOutstanding: Float!
  """The commission paid over all time."""
  lifetimePaid: Float!
  """The period the figures are for."""
  period: String!
  """
  True when the rep's role has no active rate, so the default rate is an unconfigured 0 and not a configured 0%.
  """
  rateMissing: Boolean!
  """This month's commission locked."""
  thisMonthLocked: Float!
  """How many orders earned commission this month."""
  thisMonthOrders: Int!
  """This month's commission paid."""
  thisMonthPaid: Float!
  """This month's commission still pending."""
  thisMonthPending: Float!
  """This month's commission, pending plus locked plus paid."""
  thisMonthTotal: Float!
}

"""Company settings."""
input CompanySettingsInput {
  """The address as one line."""
  address: String
  """The city."""
  addressCity: String
  """The country."""
  addressCountry: String
  """The latitude of the address on the map, as text."""
  addressLatitude: String
  """The longitude of the address on the map, as text."""
  addressLongitude: String
  """The postal code."""
  addressPostalCode: String
  """The state or region."""
  addressState: String
  """The first line of the street address."""
  addressStreet1: String
  """The second line of the street address."""
  addressStreet2: String
  """The name of the company."""
  companyName: String
  "Email address."
  email: String
  """The default language."""
  language: String
  """The URL of the company logo."""
  logo: String
  "Phone number."
  phone: String
  """The company's tax ID."""
  taxId: String
  """The time zone."""
  timezone: String
  """The company's website."""
  website: String
}

"""Input to compose and send a new email from the inbox."""
input ComposeEmailInput {
  """The email body as HTML."""
  bodyHtml: String!
  """Addresses to copy."""
  ccEmails: [String!]
  """The ID of the document the email relates to."""
  referenceId: ID
  """Type of document the email relates to."""
  referenceType: EmailReferenceType
  """Subject line."""
  subject: String!
  """Recipient addresses."""
  toEmails: [String!]!
}

"""Confirms a draft payment so it posts and can be allocated."""
input ConfirmPaymentInput {
  """
  The version of the payment you last read. The change is refused if someone else changed it since.
  """
  expectedVersion: Int
  """The ID of the draft payment to confirm."""
  paymentId: ID!
}

"""
An AI app the signed-in staff user approved on the consent screen, which still holds a live grant for them in their current organization.
"""
type ConnectedApp {
  """Live token families: each approval on the consent screen starts one."""
  activeGrantCount: Int!
  """The OAuth client_id the app registered with."""
  clientId: String!
  """
  The name the app registered with (client_name), as stored at registration. Null when it registered none.
  """
  clientName: String
  """When the earliest live grant was first issued."""
  firstConnectedAt: DateTime!
  """When the app was last issued a token (code exchange or refresh)."""
  lastTokenIssuedAt: DateTime!
  """Scopes held across the app's live grants."""
  scopes: [String!]!
}

"""A channel consent is given for: WHATSAPP, PUSH, EMAIL or SMS."""
enum ConsentChannel {
  """Email."""
  EMAIL
  """Push notifications."""
  PUSH
  """Text messages."""
  SMS
  """WhatsApp messages."""
  WHATSAPP
}

"""What a consent is for: UTILITY messages, MARKETING, or BROADCAST."""
enum ConsentPurpose {
  """Messages sent to many contacts at once."""
  BROADCAST
  """Promotional messages."""
  MARKETING
  """Messages about an order or an account."""
  UTILITY
}

"""
How consent was given: BUYER_APP, PORTAL, REP_ATTESTED, INBOUND_REPLY, ADMIN, IMPORT, RESTOCK_REQUEST or CAMPAIGN_LINK.
"""
enum ConsentSource {
  """Recorded by an admin."""
  ADMIN
  """Given in the buyer app."""
  BUYER_APP
  """Given through a campaign link."""
  CAMPAIGN_LINK
  """Brought in with an import."""
  IMPORT
  """Given by replying to a message."""
  INBOUND_REPLY
  """Given in the customer portal."""
  PORTAL
  """Recorded by a sales rep on the customer's behalf."""
  REP_ATTESTED
  """Given when asking for a restock alert."""
  RESTOCK_REQUEST
}

"""Whether a contact opted in or out: OPTED_IN or OPTED_OUT."""
enum ConsentStatus {
  """The contact agreed to receive messages."""
  OPTED_IN
  """The contact refused or withdrew consent."""
  OPTED_OUT
}

"""A contact of a customer or vendor."""
type Contact {
  """Full display name, kept as `First Last`."""
  contactName: String
  """The person's job title."""
  contactTitle: String
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The person's department."""
  department: String
  "The ID of the user who created the record."
  enteredBy: String!
  """The person's first name."""
  firstName: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """A label for the contact."""
  label: String
  """The person's last name."""
  lastName: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes about the contact."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  "The ID of the partner."
  partnerId: String!
  """The best time to reach them."""
  preferredTime: String
  """Whether this is the primary or a secondary contact."""
  priority: String!
  """
  The contact PERSON's permanent reference — `<partner code>-<8 hex>`, e.g. `C000110-a3f91b7e`. Minted once at creation from a random UUID and STORED, so it survives every later edit to the person's name, email, phone or title. Replaces the old `<code>@<firstnamelastname>` string, which was derived on read and so was neither unique (two people with one name collided) nor stable (a typo fix changed it). Shared by every CHANNEL row of one person (phone/whatsapp/email), because it identifies the person, not the row — so it is deliberately NOT unique per row. Round-trip it on update: a save that omits it falls back to matching the row by id or by type+value. Null for a partner with no code.
  """
  referenceId: String
  """Their time zone."""
  timeZone: String
  """The kind of contact, for example email or phone."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """
  The customer login (User.userType = CUSTOMER) this contact person IS. Re-resolved by name match on every partner write — never settable by the client. Null for the majority of contacts, who are not portal users.
  """
  userId: ID
  """The email address or phone number."""
  value: String!
}

"""A contact's consent for one channel and purpose."""
type ContactConsentGql {
  """The channel the consent is for."""
  channel: ConsentChannel!
  """The ID of the contact."""
  contactId: ID!
  "The unique ID of this record."
  id: ID!
  """When it was given."""
  occurredAt: DateTime!
  "The ID of the partner."
  partnerId: ID!
  """What the consent is for."""
  purpose: ConsentPurpose!
  """How the consent was given."""
  source: ConsentSource!
  """Whether the contact opted in or out."""
  status: ConsentStatus!
}

"""
Emails and phone numbers to check before saving, to see whether they belong to another person.
"""
input ContactIdentityCheckInput {
  """The email addresses to check."""
  emails: [String!]! = []
  """
  The customer being edited. Omitted for a customer that does not exist yet.
  """
  partnerId: ID
  """The phone numbers to check."""
  phones: [String!]! = []
  """
  The contact person being edited (their referenceId) — their own rows never collide. Omitted when adding a new person.
  """
  referenceId: String
}

"""Another contact that already uses an email address or phone number."""
type ContactIdentityConflictInfo {
  """EMAIL or PHONE."""
  channel: String!
  """The name of the contact."""
  contactName: String
  """The exact sentence the save would be refused with."""
  message: String!
  """The code of the partner the contact belongs to."""
  partnerCode: String
  """Null when the holder is outside the caller's scope."""
  partnerId: ID
  """The name of the partner the contact belongs to."""
  partnerName: String
  """Held by another person on the same customer."""
  samePartner: Boolean!
  """CONTACT or LOGIN."""
  source: String!
  """The value as it was checked."""
  value: String!
}

"""Priority of contact (PRIMARY, SECONDARY, EMERGENCY)"""
enum ContactPriority {
  """Called first when something urgent happens."""
  EMERGENCY
  """The main contact."""
  PRIMARY
  """An additional contact."""
  SECONDARY
}

"""
Type of contact (PHONE, EMAIL, FAX, WEBSITE, SOCIAL_MEDIA, WHATSAPP, TELEGRAM, SKYPE)
"""
enum ContactType {
  """An accounts contact."""
  ACCOUNTING
  """An email address."""
  EMAIL
  """A fax number."""
  FAX
  """A phone number."""
  PHONE
  """A sales contact."""
  SALES
  """A Skype name."""
  SKYPE
  """A social media account."""
  SOCIAL_MEDIA
  """A technical contact."""
  TECHNICAL
  """A Telegram account."""
  TELEGRAM
  """A warehouse contact."""
  WAREHOUSE
  """A website address."""
  WEBSITE
  """A WhatsApp number."""
  WHATSAPP
}

"""
Why an approved request's held action did not run. The request stays approved, so it can be applied again or by someone else.
"""
type ControlApplyRefusal {
  """
  The approval request a control refusal points at, if any (for example a new request the re-run raised).
  """
  approvalRequestId: String
  """
  The refusal code: ALREADY_APPLIED, APPLY_IN_PROGRESS, APPROVAL_EXPIRED, NOT_APPROVED, NOT_REQUESTER, APPLY_NOT_PERMITTED, APPLY_NOT_AVAILABLE, or the code the action itself refused with (for example CONTROL_BLOCKED).
  """
  code: String!
  """The control decision behind a control refusal, if any."""
  decisionId: String
  """What went wrong, for the person."""
  message: String!
}

"""One person's signature or recall on an approval request."""
type ControlApprovalAction {
  """Their name."""
  actorName: String!
  """Who did it."""
  actorUserId: String!
  """When."""
  createdAt: DateTime!
  """The action's ID."""
  id: ID!
  """What they did."""
  kind: ControlApprovalActionKind!
  """Whom they covered for, when they signed under a cover."""
  onBehalfOfName: String
  """The reason or note given."""
  reason: String
  """The cover they signed under, when they signed for someone."""
  viaDelegationId: String
}

"""What one person did on an approval request."""
enum ControlApprovalActionKind {
  """Approved it."""
  APPROVE
  """The requester recalled it."""
  RECALL
  """Rejected it."""
  REJECT
  """Returned it to the requester."""
  RETURN
}

"""
The outcome of applying an approved request: the request as it stands, and whether its held action ran.
"""
type ControlApprovalApplyResult {
  """True when the held action ran and the request is marked applied."""
  applied: Boolean!
  """Why the action did not run; null when it ran."""
  refusal: ControlApplyRefusal
  """The approval request after the attempt."""
  request: ControlApprovalRequest!
}

"""Which approval requests the inbox lists."""
enum ControlApprovalBox {
  """Every request; needs settings:controls:manage."""
  ALL
  """Requests you raised."""
  RAISED_BY_ME
  """Pending requests you may decide now."""
  TO_DECIDE
}

"""Approver coverage for some approval permissions, with setup warnings."""
type ControlApprovalCoverageType {
  """One entry per permission asked about."""
  items: [ControlApproverCoverageType!]!
  """
  Warnings over the organization's enabled controls and these permissions.
  """
  warnings: [ControlSetupWarningType!]!
}

"""
A cover: for a date range, one person may decide approval requests needing the listed permissions on behalf of another, never beyond what that person still holds.
"""
type ControlApprovalDelegation {
  """When it was set."""
  createdAt: DateTime!
  """When the cover ends (not included)."""
  endsAt: DateTime!
  """Who set it."""
  enteredBy: String!
  """Whom the cover stands in for."""
  fromUserId: String!
  """The cover's ID."""
  id: ID!
  """Whether it is running now: started, not ended, not revoked."""
  isActive: Boolean!
  """The approval permissions covered."""
  permissions: [String!]!
  """Why it was set."""
  reason: String
  """When it was revoked, if it was."""
  revokedAt: DateTime
  """Who revoked it, if anyone did."""
  revokedBy: String
  """When the cover starts."""
  startsAt: DateTime!
  """Who covers."""
  toUserId: String!
}

"""Which approval covers to list."""
enum ControlApprovalDelegationScope {
  """Every cover; needs approvals:delegation:manage."""
  ALL
  """Covers you gave or were given."""
  MINE
}

"""A request raised by a control that needs approval."""
type ControlApprovalRequest {
  """Signatures and recalls, oldest first."""
  actions: [ControlApprovalAction!]!
  """True when an AI agent raised it for the requester."""
  aiAgent: Boolean!
  """When the approved action ran."""
  appliedAt: DateTime
  """Who ran it."""
  appliedBy: String
  """That person's name."""
  appliedByName: String
  """
  True when you hold the permission to run its action; checked again when you do.
  """
  canApply: Boolean!
  """True when you may approve, reject or return it now."""
  canDecide: Boolean!
  """True when you may recall it now."""
  canRecall: Boolean!
  """Where it came from, e.g. admin or sales_app."""
  channel: String!
  """The checkpoint it was raised at, e.g. order.confirm."""
  checkpoint: String!
  """The control that raised it."""
  controlId: String!
  """The control's rule at that version."""
  controlSnapshot: JSON!
  """The control's name at that version."""
  controlTitle: String!
  """The control's version when it was raised."""
  controlVersion: Int!
  """When it was raised."""
  createdAt: DateTime!
  """
  The values the control saw when the request was raised; only on a single request read, null when not recorded.
  """
  decisionConditions: [ControlTestConditionType!]
  """The control decision that raised it."""
  decisionId: String!
  """The document's ID."""
  documentId: String!
  """The document's number, when known."""
  documentNumber: String
  """The document's type, e.g. SalesOrder."""
  documentType: String!
  """When it expires."""
  expiresAt: DateTime
  """The request's ID."""
  id: ID!
  """That person's name."""
  onBehalfOfName: String
  """Whom the requester acted for."""
  onBehalfOfUserId: String
  """The approval permission that may sign it."""
  permission: String!
  """The requester's name."""
  requesterName: String!
  """staff, customer or system."""
  requesterPrincipal: String!
  """Who raised it."""
  requesterUserId: String!
  """When it was decided, recalled or expired."""
  resolvedAt: DateTime
  """Who decided or recalled it."""
  resolvedBy: String
  """That person's name."""
  resolvedByName: String
  """Where the request stands."""
  state: ControlApprovalState!
  """Why it is in that state."""
  stateReason: String
  """True when you raised it."""
  viewerIsRequester: Boolean!
}

"""A page of approval requests."""
type ControlApprovalRequestConnection {
  """The requests on this page."""
  items: [ControlApprovalRequest!]!
  """How many match in all."""
  total: Int!
}

"""Which approval requests to list, one page at a time."""
input ControlApprovalRequestsFilter {
  """Which inbox box."""
  box: ControlApprovalBox!
  """Only this checkpoint."""
  checkpoint: String
  """How many to skip."""
  skip: Int! = 0
  """
  Only these states (not used by TO_DECIDE, which lists pending requests).
  """
  states: [ControlApprovalState!]
  """How many to return, up to 100."""
  take: Int! = 50
}

"""
Where an approval request stands. An applied request is APPROVED with appliedAt set.
"""
enum ControlApprovalState {
  """Approved; the action has not necessarily run."""
  APPROVED
  """Not decided or applied in time; final."""
  EXPIRED
  """Waiting for an approver."""
  PENDING
  """Withdrawn by the requester; final."""
  RECALLED
  """Rejected with a reason; final."""
  REJECTED
  """Sent back to the requester with a reason; final."""
  RETURNED
  """The document or control changed after the request; final."""
  STALE
}

"""Who could approve requests needing one approval permission."""
type ControlApproverCoverageType {
  """True when someone counted is eligible through a running cover."""
  coversActive: Boolean!
  """
  How many active staff could approve, counting running covers; you are left out unless includeMe is true.
  """
  eligibleCount: Int!
  """The approval permission."""
  permission: String!
  """Up to five of their names, sorted."""
  sample: [String!]!
}

"""One condition: a catalogue fact, an operator and a value."""
input ControlConditionInput {
  """The catalogue fact to test."""
  fact: String!
  """The operator: gt, gte, lt, eq, is, is_not or in."""
  op: String!
  """The value to compare with."""
  value: ControlValueInput!
}

"""
One condition of a control: a fact from the fixed catalogue, an operator and one value. Exactly one of number, text, list or flag is set.
"""
type ControlConditionType {
  """The catalogue fact the condition tests."""
  fact: String!
  """The value for a yes/no fact."""
  flag: Boolean
  """The values for a choice fact compared with in."""
  list: [String!]
  """The value for a money, percent or number fact."""
  number: Float
  """The operator: gt, gte, lt, eq, is, is_not or in."""
  op: String!
  """The value for a choice fact compared with is or is_not."""
  text: String
}

"""How often a control decided something in the last 30 days."""
type ControlDecisionCountsType {
  """Actions the control blocked."""
  block: Int!
  """Actions the control sent for approval."""
  needsApproval: Int!
  """Actions the control would have refused while observing."""
  observed: Int!
  """Checks the control passed."""
  passes: Int!
}

"""The latest change to a control's mode: who made it, when, and why."""
type ControlModeChangeType {
  """When the mode changed."""
  at: DateTime!
  """
  The name of the user who changed it, or null when the user no longer exists.
  """
  byName: String
  """The ID of the user who changed it."""
  byUserId: String
  """
  The mode before the change: off, observe or enforce. Null when the control was created.
  """
  fromMode: String
  """The reason given for the change, if any."""
  reason: String
  """The mode after the change."""
  toMode: String!
}

"""What the control does when its conditions match."""
input ControlOutcomeInput {
  """block or approval."""
  kind: String!
  """The message shown when a block control refuses."""
  message: String
  """The approval permission, for an approval control."""
  permission: String
  """
  Facts whose change after approval makes the approval stale. Defaults to none.
  """
  staleWhen: [String!]
}

"""
What a control does when its conditions match: block with a message, or require approval.
"""
type ControlOutcomeType {
  """block or approval."""
  kind: String!
  """The message shown when a block control refuses."""
  message: String
  """The permission a person needs to approve, for an approval control."""
  permission: String
  """
  Facts whose change after approval makes the approval stale (approval controls only).
  """
  staleWhen: [String!]!
}

"""A value to fill before a preset can be enabled."""
type ControlPresetInputNeedType {
  """The condition's position, from 0."""
  conditionIndex: Int!
  """The part to fill: value."""
  field: String!
}

"""A ready-made control to start from."""
type ControlPresetType {
  """The checkpoint the control runs at."""
  checkpoint: String!
  """The conditions."""
  conditions: [ControlConditionType!]!
  """The mode it is saved in: off."""
  defaultMode: String!
  """The translation key for its summary."""
  descriptionKey: String!
  """all or any of the conditions."""
  join: String!
  """The control's name once saved."""
  name: String!
  """Values the organization fills before enabling it."""
  needsInput: [ControlPresetInputNeedType!]!
  """What a match does."""
  outcome: ControlOutcomeType!
  """The preset's stable ID."""
  presetId: String!
  """Customers and warehouses."""
  scope: ControlScopeType!
  """The translation key for its title."""
  titleKey: String!
}

"""The latest control refusal on a document."""
type ControlRefusalSummary {
  """When."""
  at: DateTime!
  """The checkpoint it refused at."""
  checkpoint: String!
  """The control that refused."""
  controlId: String!
  """The control decision."""
  decisionId: String!
  """The message the control shows."""
  message: String!
}

"""One problem found in a control."""
type ControlRuleErrorType {
  """The problem's code, e.g. UNKNOWN_FACT or UNKNOWN_REFERENCE."""
  code: String!
  """The translation key for the problem's message."""
  messageKey: String!
  """Where in the rule the problem is, e.g. conditions[0].value."""
  path: String!
}

"""
A control: one rule checked at one checkpoint, with its mode and recent decisions.
"""
type ControlRuleType {
  """Whether the control is archived."""
  archived: Boolean!
  """The checkpoint the control runs at, e.g. order.confirm."""
  checkpoint: String!
  """The conditions, at most ten, in one level."""
  conditions: [ControlConditionType!]!
  """The control's decisions in the last 30 days."""
  counts: ControlDecisionCountsType!
  """The ID of the control."""
  id: ID!
  """
  True when the stored rule no longer passes validation. It is shown, never hidden.
  """
  invalid: Boolean!
  """Why the stored rule is invalid."""
  invalidReason: String
  """all: every condition must match; any: one is enough."""
  join: String!
  """
  The latest change to the control's mode, from the settings history. Set on the controls list; null elsewhere or when the history has none.
  """
  lastModeChange: ControlModeChangeType
  """off, observe or enforce."""
  mode: String!
  """The control's name."""
  name: String!
  """The control's position in the list."""
  order: Int!
  """What happens when the conditions match."""
  outcome: ControlOutcomeType!
  """The preset the control was created from, if any."""
  presetId: String
  """Counts every change, including mode changes."""
  revision: Int!
  """The customers and warehouses the control covers."""
  scope: ControlScopeType!
  """
  The rule version approvals bind to. It changes only when the rule itself changes.
  """
  version: Int!
}

"""The customers and warehouses a control covers."""
input ControlScopeInput {
  """Customers the control never applies to."""
  exceptCustomerIds: [String!]
  """Warehouses the control is limited to. Empty means all."""
  warehouseIds: [String!]
}

"""Where a control does not apply, or only applies."""
type ControlScopeType {
  """Customers the control never applies to."""
  exceptCustomerIds: [String!]!
  """Warehouses the control is limited to. Empty means every warehouse."""
  warehouseIds: [String!]!
}

"""The result of checking a control before it is saved or enabled."""
type ControlSetupCheckType {
  """
  How many people other than you could approve, or null when that is not known yet.
  """
  approverCount: Int
  """Every problem found."""
  errors: [ControlRuleErrorType!]!
  """Notes about checks not yet run."""
  notes: [String!]!
  """True when the control can be saved."""
  ok: Boolean!
}

"""
A setup warning: a control set that can never pass, or an approval permission only one person holds.
"""
type ControlSetupWarningType {
  """
  PREPAID_UNVERIFIABLE: a payment-gated control is on while no control verifies payments at settle, so offline payments never pass it. SINGLE_APPROVER: exactly one person can approve the permission and no cover is running.
  """
  code: String!
  """The enabled controls the warning is about."""
  controlIds: [ID!]!
  """The approval permission, for SINGLE_APPROVER; else null."""
  permission: String
}

"""One condition of a tested control, on a record."""
type ControlTestConditionType {
  """A yes/no actual."""
  actualFlag: Boolean
  """A numeric actual."""
  actualNumber: Float
  """A choice actual."""
  actualText: String
  """The catalogue fact tested."""
  fact: String!
  """The operator, e.g. gt or is."""
  op: String!
  """Whether it matched; null (no value) never matches."""
  result: Boolean
  """The condition as set."""
  value: ControlConditionType!
}

"""What a control would decide for one record."""
type ControlTestResultType {
  """Each condition's result, when the control matched."""
  conditions: [ControlTestConditionType!]!
  """Notes, e.g. facts with no value."""
  notes: [String!]!
  """PASS, BLOCK or NEEDS_APPROVAL."""
  outcome: String!
  """True unless the outcome is PASS."""
  wouldRefuse: Boolean!
}

"""A condition value. Set exactly one field, matching the fact's type."""
input ControlValueInput {
  """For a yes/no fact."""
  flag: Boolean
  """For a choice fact compared with in."""
  list: [String!]
  """For a money, percent or number fact."""
  number: Float
  """For a choice fact compared with is or is_not."""
  text: String
}

"""One saved version of a control."""
type ControlVersionType {
  """Whether the control was archived at that change."""
  archived: Boolean!
  """The reason given for the change."""
  changeReason: String
  """When the change was made."""
  createdAt: DateTime!
  """The ID of the user who made the change."""
  createdBy: String
  """The mode at that change."""
  mode: String!
  """The change number this version records."""
  revision: Int!
  """The control as it was at that change."""
  rule: ControlRuleType!
  """The rule version at that change."""
  version: Int!
}

"""The switch that makes every control observe."""
type ControlsKillSwitchType {
  """True while controls only observe."""
  active: Boolean!
  """The last reason."""
  reason: String
  """When it last changed."""
  setAt: DateTime
  """Who set it last."""
  setBy: String
}

"""A quantity and the two units to convert between."""
input ConvertQuantityInput {
  """The ID of the unit to convert from."""
  fromUOMId: String!
  """
  The ID of a product whose own pack conversions to use, when it has them.
  """
  productId: String
  """The quantity to convert, in the from unit. Must not be negative."""
  quantity: Float!
  """The ID of the unit to convert to. It must be in the same category."""
  toUOMId: String!
}

"""The converted quantity and the factor used."""
type ConvertQuantityResult {
  """The factor the quantity was multiplied by."""
  conversionFactor: Float!
  """The quantity in the to unit."""
  convertedQuantity: Float!
  """The converted quantity with its unit symbol."""
  formatted: String!
  """The unit converted from."""
  fromUOM: UnitOfMeasure!
  """The unit converted to."""
  toUOM: UnitOfMeasure!
}

"""The vendor terms for a customer who is also made a vendor."""
input ConvertToVendorInput {
  """True when the vendor agreement renews by itself."""
  autoRenewal: Boolean
  """The vendor's business category."""
  businessCategory: String
  """The vendor's certifications."""
  certifications: [String!]
  """The days within which paying early earns a discount."""
  earlyPaymentDays: Int
  """The discount for paying early, in percent."""
  earlyPaymentDiscount: Int
  """The expected days from order to delivery."""
  leadTimeDays: Int
  """The payment terms the vendor gives."""
  paymentTerms: String
  """The product categories the vendor supplies."""
  productCategories: [String!]
  """The areas the vendor serves."""
  serviceAreas: [String!]
  """The kind of vendor."""
  vendorType: String
}

"""
The caller's standing approval rules, for low-risk proposals only. The available flags say whether the organization has switched the feature on.
"""
type CopilotApprovalRulesType {
  """True when the organization allows automatic approval."""
  autoApproveAvailable: Boolean!
  """True when low-risk proposals are approved automatically."""
  autoApproveLow: Boolean!
  """True when low-risk proposals are approved for this conversation."""
  sessionLowTier: Boolean!
  """True when the organization allows approving by text."""
  textApprovalAvailable: Boolean!
}

"""
How much this organization lets the copilot do. It is a ceiling the organization sets beneath the one permissions already give.
"""
type CopilotAutonomyCapType {
  """
  full for everything, no_money to leave out money actions, or read_only to only read.
  """
  level: String!
  """
  organization when an admin set it, default when nobody has, which means full.
  """
  source: String!
}

"""A background job started by the copilot."""
type CopilotJob {
  """Why the job failed."""
  error: String
  """The ID of the job."""
  jobId: ID!
  """What the job does."""
  kind: CopilotJobKind!
  """How far the job has got."""
  progress: JSON!
  """A report of the result."""
  report: JSON
  """Where the job stands."""
  status: CopilotJobStatus!
  """When the job last changed, in epoch milliseconds."""
  updatedAt: Float!
}

"""
What a copilot job does: PARSE a file, APPLY a proposal, or source IMAGES.
"""
enum CopilotJobKind {
  """Applies approved Copilot changes."""
  APPLY
  """Finds images for products."""
  IMAGES
  """Reads an uploaded file into proposals."""
  PARSE
}

"""Where a copilot job stands: PENDING, RUNNING, COMPLETED or FAILED."""
enum CopilotJobStatus {
  """Finished successfully."""
  COMPLETED
  """Stopped with an error."""
  FAILED
  """Queued and not started."""
  PENDING
  """In progress."""
  RUNNING
}

"""
A CONSTRAINT is a rule the user set and the copilot must honour; a PREFERENCE is a default; CONTEXT is background.
"""
enum CopilotMemoryCategory {
  """A rule Copilot must follow."""
  CONSTRAINT
  """A background fact about the business."""
  CONTEXT
  """A way the user likes things done."""
  PREFERENCE
}

"""A fact the copilot remembers."""
type CopilotMemoryFactType {
  """What kind of fact: a constraint, a preference or background."""
  category: CopilotMemoryCategory!
  """How sure the copilot is, from 0 to 1."""
  confidence: Float
  """
  lowercase_snake label the fact is stored under, e.g. preferred_quote_currency. It is the id `forgetCopilotMemoryFact` takes.
  """
  key: String!
  """STATED, INFERRED or RECORDED; null when unknown."""
  origin: String
  """The conversation the fact was learned in."""
  sourceSessionId: ID
  """Whose fact it is: the user's own or the organization's."""
  subjectType: CopilotMemorySubjectType!
  """When the fact last changed, in epoch milliseconds."""
  updatedAt: Float!
  """The fact."""
  value: String!
}

"""
Whose memory: the signed-in user's own facts, or the organization-wide ones.
"""
enum CopilotMemorySubjectType {
  """A fact that applies to the whole organization."""
  TENANT
  """A fact that applies to one user."""
  USER
}

"""
Whether the copilot may remember anything for the caller, and where that was decided.
"""
type CopilotMemorySwitchType {
  """True when memory is on for the caller."""
  enabled: Boolean!
  """
  True when the organization has learning switched on. The console hides the row otherwise.
  """
  learningAvailable: Boolean!
  """
  True when the copilot learns from the caller's activity. Off whenever memory is off.
  """
  learningEnabled: Boolean!
  """
  True when the organization turned learning or memory off, so the console locks the row.
  """
  learningLocked: Boolean!
  """True when the console may ask why a card was rejected."""
  learningSignals: Boolean!
  """
  Where the learning setting comes from: user, organization, default or unavailable.
  """
  learningSource: String!
  """
  True when the organization turned memory off and one person cannot turn it back on for themselves.
  """
  organizationLocked: Boolean!
  """
  The playbook mode: off, shadow or on. The console shows the playbook editor unless it is off.
  """
  playbookMode: String!
  """
  Where the setting comes from: user, organization, default or unavailable.
  """
  source: String!
}

"""One message in a copilot conversation."""
type CopilotMessage {
  """The IDs of the proposal cards the message produced."""
  cardIds: [String!]
  """When it was written, in epoch milliseconds."""
  createdAt: Float!
  """The feedback the user gave on the message."""
  feedback: JSON
  "The unique ID of this record."
  id: ID!
  """Who wrote it."""
  role: String!
  """The text of the message."""
  text: String
  """
  The tools the turn used, so a reopened conversation still shows what it did.
  """
  toolCalls: JSON
  """What the turn cost: tokens, credits and the model used."""
  usage: JSON
}

"""
Messages older than a given message, oldest first — reads a long chat back past its newest window.
"""
type CopilotMessagePage {
  """True when there are older messages."""
  hasMore: Boolean!
  """The messages on this page."""
  messages: [CopilotMessage!]!
}

"""A model the copilot can use."""
type CopilotModelInfo {
  """The name to show."""
  displayName: String!
  """The cost per million input tokens."""
  inputCostPerM: Float!
  """True when this is the cheapest model."""
  isCheapest: Boolean!
  """The key of the model."""
  modelKey: String!
  """The cost per million output tokens."""
  outputCostPerM: Float!
}

"""
A saved prompt: work a workspace does every week, written down once. It is inserted as the seller's own message and nothing more.
"""
type CopilotPromptTemplateType {
  """The text inserted as the seller's message, word for word."""
  body: String!
  """The handle an admin types, unique within the organization."""
  slug: String!
  """The title of the prompt."""
  title: String!
}

"""
What a copilot proposal does, for example draft a quote, create a customer, record a payment or adjust stock. Some kinds can be stored but are not yet produced or applied.
"""
enum CopilotProposalKind {
  """A message sent to many contacts."""
  BROADCAST
  """A change to the category tree."""
  CATEGORY_TREE
  """A new credit note."""
  CREDIT_NOTE
  """Applying a credit note to an invoice."""
  CREDIT_NOTE_APPLICATION
  """A new customer."""
  CUSTOMER_CREATE
  """A new debit note."""
  DEBIT_NOTE
  """A drafted email."""
  EMAIL_DRAFT
  """Receiving goods against a purchase order."""
  GRN_RECEIPT
  """Finding images for products."""
  IMAGE_SOURCING
  """A new invoice."""
  INVOICE_CREATE
  """A status change on an invoice."""
  INVOICE_TRANSITION
  """An edit to an invoice."""
  INVOICE_UPDATE
  """A catalog operation."""
  OPERATION
  """An edit to a customer or supplier."""
  PARTNER_UPDATE
  """Allocating a payment to invoices."""
  PAYMENT_ALLOCATION
  """Recording a payment."""
  PAYMENT_RECORD
  """A post to publish."""
  POST_PUBLISH
  """Archiving products."""
  PRODUCT_ARCHIVE
  """Importing products."""
  PRODUCT_IMPORT
  """A list of products."""
  PRODUCT_LIST
  """An edit to products."""
  PRODUCT_UPDATE
  """A new draft purchase order."""
  PURCHASE_ORDER_DRAFT
  """A status change on a purchase order."""
  PURCHASE_ORDER_TRANSITION
  """An edit to a purchase order."""
  PURCHASE_ORDER_UPDATE
  """Converting a quote to an order."""
  QUOTE_CONVERSION
  """A new draft quote."""
  QUOTE_DRAFT
  """A status change on a quote."""
  QUOTE_STATUS
  """An edit to a quote."""
  QUOTE_UPDATE
  """Processing a return."""
  RETURN_PROCESS
  """A change to a user's role."""
  ROLE_CHANGE
  """A new draft sales order."""
  SALES_ORDER_DRAFT
  """Fulfilling a sales order."""
  SALES_ORDER_FULFILMENT
  """A status change on a sales order."""
  SALES_ORDER_TRANSITION
  """An edit to a sales order."""
  SALES_ORDER_UPDATE
  """An invitation to a new staff member."""
  STAFF_INVITE
  """A stock count adjustment."""
  STOCK_ADJUSTMENT
  """A stock transfer between warehouses."""
  STOCK_TRANSFER
  """A new supplier."""
  SUPPLIER_CREATE
  """A set of product variants."""
  VARIANT_MATRIX
  """A weekly plan."""
  WEEKLY_PLAN
}

"""
Where a copilot proposal stands: PROPOSED, APPROVED, REJECTED, APPLYING, APPLIED, FAILED, REPRICE_REQUIRED when a re-price found drift before applying, or SUPERSEDED when a newer card replaced it.
"""
enum CopilotProposalStatus {
  """The change was made."""
  APPLIED
  """The change is being made."""
  APPLYING
  """Approved and waiting to be applied."""
  APPROVED
  """Applying the change failed."""
  FAILED
  """Waiting for a decision."""
  PROPOSED
  """Turned down."""
  REJECTED
  """
  Prices changed since the proposal; it must be priced again before it can be approved.
  """
  REPRICE_REQUIRED
  """Replaced by a newer proposal."""
  SUPERSEDED
}

"""Whether a scheduled copilot job is active or PAUSED."""
enum CopilotScheduledJobStatus {
  """Runs on its schedule."""
  ACTIVE
  """Not running until resumed."""
  PAUSED
}

"""A prompt the copilot runs on a schedule."""
type CopilotScheduledJobType {
  """When the job was created, in epoch milliseconds."""
  createdAt: Float!
  """The schedule, as a cron expression."""
  cron: String!
  "The unique ID of this record."
  id: ID!
  """The error from the last run, if it failed."""
  lastError: String
  """When the job last ran, in epoch milliseconds."""
  lastRunAt: Float
  """The conversation the last run produced."""
  lastSessionId: ID
  """The name of the job."""
  name: String!
  """The prompt that is run."""
  prompt: String!
  """The ID of the skill the job uses."""
  skillId: String!
  """Whether the job is active or paused."""
  status: CopilotScheduledJobStatus!
  """The time zone the schedule runs in."""
  timezone: String!
  """The tools the job may use."""
  toolNames: [String!]!
  """When the job last changed, in epoch milliseconds."""
  updatedAt: Float!
}

"""A copilot conversation."""
type CopilotSession {
  """
  The ID of the run still writing the end of the conversation, so a client can replay its events.
  """
  activeRunId: String
  """When it started, in epoch milliseconds."""
  createdAt: Float!
  """True when the conversation holds a parsed file."""
  hasIr: Boolean!
  "The unique ID of this record."
  id: ID!
  """A summary of the parsed file."""
  irSummary: JSON
  """The messages."""
  messages: [CopilotMessage!]!
  """When the owner pinned this chat (epoch ms); null = not pinned."""
  pinnedAt: Float
  """The proposal cards."""
  proposals: [ProposalCardType!]!
  """
  True while a turn is being generated for this conversation, so a client knows to reattach.
  """
  runActive: Boolean
  """Working state of the conversation, for the same user and organization."""
  scratchpad: JSON
  """The status of the conversation."""
  status: String!
  """The title of the conversation."""
  title: String
  """When it last changed, in epoch milliseconds."""
  updatedAt: Float!
}

"""
One page of the caller's own chat history — pinned first, then most recent.
"""
type CopilotSessionHistoryPage {
  """Pass as `after` for the next page."""
  endCursor: String
  """True when there are more after this page."""
  hasNextPage: Boolean!
  """The conversations on this page."""
  items: [CopilotSessionSummary!]!
}

"""One row in the user's own conversation list."""
type CopilotSessionSummary {
  """
  How many proposal cards in this chat still wait for the owner's decision (proposed, or waiting for a re-price). A chat started by a connected app (MCP) holds its cards here.
  """
  awaitingApprovalCount: Int!
  """When it started, in epoch milliseconds."""
  createdAt: Float!
  "The unique ID of this record."
  id: ID!
  """When the last message was written, in epoch milliseconds."""
  lastMessageAt: Float
  """When the owner pinned this chat (epoch ms); null = not pinned."""
  pinnedAt: Float
  """
  Search only: an excerpt of the newest message that matched — why this chat is in the results.
  """
  snippet: String
  """The status of the conversation."""
  status: String!
  """The title of the conversation."""
  title: String
}

"""
How many turns each buyer may have with the shopping assistant per day.
"""
type CopilotShopperTurnCapType {
  """True when the plan gives this seller's buyers the assistant at all."""
  available: Boolean!
  """The highest value allowed."""
  max: Int!
  """The lowest value allowed."""
  min: Int!
  """The recommended value."""
  recommended: Int!
  """
  Where it comes from: organization when the seller set it, platform for the default, or default for the recommended value.
  """
  source: String!
  """
  The turns per buyer per UTC day in force. 0 means buyers have no assistant.
  """
  turns: Int!
}

"""The defaults of a country, used to set up an organization."""
type CountryDefaults {
  """The country code."""
  countryCode: String!
  """The name of the country."""
  countryName: String!
  "ISO 4217 currency code."
  currencyCode: String!
  """The name of the country's currency."""
  currencyName: String!
  """The symbol of the country's currency."""
  currencySymbol: String!
  """The usual date format."""
  dateFormat: String!
  """The main time zone."""
  defaultTimezone: String!
  """When the fiscal year starts, as MM-DD."""
  fiscalYearStart: String!
  """How many states or regions the country has."""
  statesCount: Int!
  """The tax system the country uses."""
  taxSystem: String
  """The usual time format."""
  timeFormat: String!
  """The time zones of the country."""
  timezones: [String!]!
}

"""A country to pick from."""
type CountryListItem {
  """The country code."""
  code: String!
  "ISO 4217 currency code."
  currencyCode: String!
  """The name of the country's currency."""
  currencyName: String!
  """The flag."""
  flag: String!
  """The name of the country."""
  name: String!
  """The dialling code."""
  phoneCode: String!
}

"""
Who pays the difference when staff change the courier: KEEP_CUSTOMER_PRICE (the customer pays the lower of their agreed price and the new courier charge; the seller pays the rest) or SELLER_PAYS_ALL (the customer pays nothing; the seller pays the whole charge).
"""
enum CourierCostPolicy {
  """
  The customer pays the lower of their agreed price and the new courier charge; the seller pays the rest.
  """
  KEEP_CUSTOMER_PRICE
  """The customer pays nothing and the seller pays the whole charge."""
  SELLER_PAYS_ALL
}

"""The total of one currency in a batch of courier payments."""
type CourierPaymentBatchTotalGql {
  """The sum of the courier charges settled, as a decimal string."""
  amount: String!
  "ISO 4217 currency code."
  currency: String!
  """How many shipments it covers."""
  shipmentCount: Int!
}

"""
The order's courier plan: the customer's original choice and price, the active staff change (null after Use Customer's Choice) and the history. Staff only.
"""
type CourierPlan {
  """The active staff change. Null when the customer's choice applies."""
  current: CourierPlanChange
  """Every change and revert, oldest first, capped at the newest 50."""
  history: [CourierPlanEntry!]!
  """
  Why the courier cannot be changed now (invoiced, shipped, cancelled, and so on). Null while a change is allowed.
  """
  lockReason: String
  """The customer's original courier choice and shipping price."""
  original: CourierPlanOriginal!
  """
  Why a courier change made now would keep the customer's share at the order's current shipping: PAID or ONLINE_CHECKOUT; null when the share would move. For the order as it stands, with or without a current change.
  """
  shareHold: CourierShareHoldReason
}

"""
One staff change of the courier: the new service, its charge, who pays what, why, who and when. Staff only.
"""
type CourierPlanChange {
  """When the change was made."""
  changedAt: DateTime!
  """The ID of the user who made the change."""
  changedById: String!
  """Display name of the user who made the change."""
  changedByName: String
  "ISO 4217 currency code."
  currency: String!
  """The amount billed to the customer for shipping, as a decimal string."""
  customerShare: String!
  """
  True when the order was already paid, or its online amount was fixed, so the customer's share stayed unchanged.
  """
  customerShareHeldBecausePaid: Boolean!
  """Why the customer's share was held. Null when it was not."""
  heldReason: CourierShareHoldReason
  """
  The courier charge priced by the server when the change was made, as a decimal string.
  """
  plannedCost: String!
  """Who bears the courier cost."""
  policy: CourierCostPolicy!
  """Why staff made the change. Null when no reason was given."""
  reason: String
  """
  The part of the courier charge the seller absorbs (planned cost minus customer share, never below 0), as a decimal string.
  """
  sellerShare: String!
  """The courier service the order was changed to."""
  service: PlannedCourierService!
}

"""
One history entry: a CHANGE (with its figures) or a REVERT to the customer's choice (who and when only).
"""
type CourierPlanEntry {
  """The figures of the change. Set only when the entry is a CHANGE."""
  change: CourierPlanChange
  """When the entry was made."""
  changedAt: DateTime!
  """The ID of the user who made the entry."""
  changedById: String!
  """Display name of the user who made the entry."""
  changedByName: String
  """
  Whether the entry is a CHANGE of courier or a REVERT to the customer's choice.
  """
  kind: CourierPlanEntryKind!
}

"""
CHANGE: staff changed the courier. REVERT: staff went back to the customer's choice.
"""
enum CourierPlanEntryKind {
  """Staff changed the courier."""
  CHANGE
  """Staff went back to the customer's choice."""
  REVERT
}

"""What the customer agreed before any staff change."""
type CourierPlanOriginal {
  """
  The order's shipping charge before the first staff change, as a decimal string.
  """
  amount: String!
  "ISO 4217 currency code."
  currency: String!
  """
  The courier the customer picked at checkout. Null when the order had none (staff-entered or flat fee).
  """
  service: PlannedCourierService
}

"""
Why the customer's share stayed at the order's shipping: PAID (a payment is recorded; never lowered) or ONLINE_CHECKOUT (the online payment amount was fixed at checkout).
"""
enum CourierShareHoldReason {
  """The online payment amount was fixed at checkout."""
  ONLINE_CHECKOUT
  """A payment is recorded, so the share is never lowered."""
  PAID
}

"""An address of a partner."""
input CreateAddressInput {
  """The city."""
  city: String!
  """The email address of the contact at the address."""
  contactEmail: String
  """The name of the contact at the address."""
  contactName: String
  """The phone number of the contact at the address."""
  contactPhone: String
  """The country."""
  country: String!
  """
  The ID of an existing address to update in place, so its ID is kept. Leave out for a new address.
  """
  id: ID
  """Delivery or access instructions."""
  instructions: String
  "Whether the record is active."
  isActive: Boolean! = true
  "Whether this is the default."
  isDefault: Boolean! = false
  """True when the one address serves both billing and delivery."""
  isDualPurpose: Boolean
  """A label for the address, such as Head office."""
  label: String
  """The latitude."""
  latitude: Float
  """The longitude."""
  longitude: Float
  """The postal code."""
  postalCode: String!
  """Whether the address is the primary or a secondary one."""
  priority: AddressPriority! = SECONDARY
  """Whether the address is for a customer or a vendor role."""
  role: PartnerRole
  """The state or region."""
  state: String!
  """The first line of the street address."""
  street1: String!
  """The second line of the street address."""
  street2: String
  """The kind of address, for example billing or shipping."""
  type: AddressType!
}

"""Starts a purchase of AI credits."""
input CreateAiCreditCheckoutInput {
  """The amount to buy, in cents."""
  amountCents: Int!
  """Where to send the buyer if they cancel."""
  cancelUrl: String!
  """Where to send the buyer after paying."""
  successUrl: String!
}

"""A new API key."""
input CreateApiKeyInputGql {
  """
  IP allowlist — IPv4/IPv6 addresses or CIDR ranges (e.g. 203.0.113.7, 10.0.0.0/8). Empty = any IP
  """
  allowedIps: [String!]
  """Optional absolute expiry (must be in the future)"""
  expiresAt: DateTime
  """
  Expire this many days from now (1–3650); expiresAt wins when both are given
  """
  expiresInDays: Int
  """Friendly name for the API key"""
  name: String!
  """Rate limit in requests per minute (default: 100)"""
  rateLimit: Int
  """Access scope: READ_ONLY or READ_WRITE"""
  scope: ApiKeyScope = READ_ONLY
}

"""A new bank account."""
input CreateBankAccountInput {
  """The name the account is known by in the organization."""
  accountName: String!
  """The account number."""
  accountNumber: String!
  """
  The kind of account, for example CURRENT or SAVINGS. Defaults to CURRENT.
  """
  accountType: String = "CURRENT"
  """The name of the bank that holds the account."""
  bankName: String!
  """The bank branch or sort code."""
  branchCode: String
  "ISO 4217 currency code."
  currencyCode: String!
  """
  The opening balance in the account's currency. Defaults to 0. Set once here. Later corrections go through adjustBankAccountBalance.
  """
  currentBalance: Float = 0
  """The IBAN."""
  iban: String
  "Whether the record is active."
  isActive: Boolean = true
  "Whether this is the default."
  isDefault: Boolean = false
  """Free-text notes about the account."""
  notes: String
  """The SWIFT or BIC code of the bank."""
  swiftCode: String
}

"""A new brand."""
input CreateBrandInput {
  """The brand code."""
  code: String!
  """What the brand is."""
  description: String
  """The URL of the brand logo."""
  logoUrl: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The name of the brand."""
  name: String!
  """The brand's website."""
  websiteUrl: String
}

"""A new category."""
input CreateCategoryInput {
  """The category code."""
  code: String!
  """What the category holds."""
  description: String
  """The URL of the category image."""
  imageUrl: String
  "Whether the record is active."
  isActive: Boolean! = true
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The name of the category."""
  name: String!
  """The ID of the parent category. Leave out for a root."""
  parentId: String
  """The position among sibling categories, lowest first."""
  sortOrder: Int! = 0
}

"""A new chat channel."""
input CreateChannelInput {
  """What the channel is for."""
  description: String
  "Whether this is the default."
  isDefault: Boolean = false
  """True when only invited people can join."""
  isPrivate: Boolean = false
  """The name of the channel."""
  name: String!
}

"""
A contact method of a partner, such as an email address or phone number.
"""
input CreateContactInput {
  """
  Full display name, kept as `First Last`. Every existing reader (global search, PDFs, address labels) still reads this; the split halves below are what a customer login is matched on.
  """
  contactName: String
  """The person's job title."""
  contactTitle: String
  """The person's department."""
  department: String
  """
  Given name. Together with lastName this derives the contact's reference id and matches the person to their customer login — which is why it is stored rather than split off contactName at the first space.
  """
  firstName: String
  """
  The ID of an existing contact to update in place, so its ID and reference are kept. Leave out for a new contact.
  """
  id: ID
  "Whether the record is active."
  isActive: Boolean! = true
  "Whether this is the default."
  isDefault: Boolean! = false
  """A label for the contact."""
  label: String
  """Family name. See firstName."""
  lastName: String
  """Notes about the contact."""
  notes: String
  """The best time to reach them."""
  preferredTime: String
  """Whether this is the primary or a secondary contact."""
  priority: ContactPriority! = SECONDARY
  """
  The permanent reference of the contact person. Send it back unchanged so a save does not make a new one.
  """
  referenceId: String
  """Whether the contact is for a customer or a vendor role."""
  role: PartnerRole
  """Their time zone."""
  timeZone: String
  """The kind of contact, for example email or phone."""
  type: ContactType!
  """The email address or phone number."""
  value: String!
}

"""A new cover. The window is at most 90 days and must end in the future."""
input CreateControlApprovalDelegationInput {
  """When the cover ends (not included)."""
  endsAt: DateTime!
  """
  Whom the cover stands in for; defaults to you. Someone else needs approvals:delegation:manage.
  """
  fromUserId: String
  """
  The approval permissions covered, each one the person covered holds now.
  """
  permissions: [String!]!
  """Why, up to 500 characters."""
  reason: String
  """When the cover starts."""
  startsAt: DateTime!
  """Who covers: active staff, not you."""
  toUserId: String!
}

"""A new chat conversation."""
input CreateConversationInput {
  """The title of the conversation."""
  title: String
}

"""A new credit note."""
input CreateCreditNoteInput {
  """A signed adjustment to the total, such as rounding."""
  adjustments: Float
  """The note amount before tax."""
  amount: Float!
  "ISO 4217 currency code."
  currency: String
  """The date after which the credit can no longer be applied."""
  expiryDate: DateTime
  """Notes for staff only. They are not shown to the customer or supplier."""
  internalNotes: String
  """The credit lines."""
  items: [CreateCreditNoteItemInput!]!
  """Notes shown on the note."""
  notes: String
  """The ID of the invoice the note is raised against."""
  originalInvoiceId: String
  "The ID of the partner."
  partnerId: String!
  """Why the note is raised."""
  reason: String!
  """The ID of the return the note comes from."""
  returnId: String
  """The tax on the note."""
  taxAmount: Float
  """
  What the note is for: SALES_RETURN, PURCHASE_RETURN, PRICE_ADJUSTMENT, GOODWILL or OTHER.
  """
  type: String!
}

"""One line of a new credit note."""
input CreateCreditNoteItemInput {
  """The line amount."""
  amount: Float!
  """What the credit is for on this line."""
  description: String!
  """The discount on the line, rounded to the currency."""
  discountAmount: Float
  """
  The exact discount for the full line quantity, before rounding. When left out it is worked out from the percent and the amount.
  """
  discountAmountExact: Float
  """The discount on the line, in percent."""
  discountPercent: Float
  "The ID of the product."
  productId: String
  """The quantity credited."""
  quantity: Float!
  """The tax on the line."""
  taxAmount: Float
  """The tax split as a list of tax type, rate and tax amount."""
  taxBreakdown: JSON
  """The tax rate on the line, in percent."""
  taxRate: Float
  """The price of one unit."""
  unitPrice: Float!
  "The ID of the product variant."
  variantId: String
}

"""A new currency."""
input CreateCurrencyInput {
  """The currency code, such as an ISO 4217 code."""
  code: String!
  """How many decimal places amounts show."""
  decimalPlaces: Int = 2
  """The character between the whole and decimal parts."""
  decimalSeparator: String = "."
  """The ID of the user who entered it."""
  enteredBy: String
  "Whether the record is active."
  isActive: Boolean = true
  """True when this is the organization's base currency."""
  isBaseCurrency: Boolean = false
  """The name of the currency."""
  name: String!
  """The position in lists, lowest first."""
  sortOrder: Int = 0
  """The currency symbol."""
  symbol: String!
  """Where the symbol goes: before or after the amount."""
  symbolPosition: String = "before"
  """The character between thousands."""
  thousandSeparator: String = ","
  """The kind of currency: fiat, crypto or commodity."""
  type: String = "FIAT"
  """The ID of the user who last changed it."""
  updatedBy: String
}

"""A payment received from a customer."""
input CreateCustomerCollectionInput {
  """
  The invoices to apply the money to and the amount for each. Leave out to keep the money on account.
  """
  allocations: [PaymentAllocationInput!]
  """The amount received, in the collection's currency. Must be positive."""
  amount: Float!
  """The ID of the bank account that received the money."""
  bankAccountId: ID
  """The date the money was received."""
  collectionDate: DateTime!
  """How the customer paid."""
  collectionMethod: CollectionMethod!
  "ISO 4217 currency code."
  currency: String!
  "The ID of the customer."
  customerId: ID!
  """
  The exchange rate to the organization's base currency. Needed when the currency is not the base currency.
  """
  exchangeRate: Float
  """
  A unique key of 8 to 128 characters. Sending the same key again returns the collection already created instead of a duplicate.
  """
  idempotencyKey: String
  """Free-text notes about the collection."""
  notes: String
  """
  The customer's reference for the payment, such as a cheque or transfer number.
  """
  referenceNumber: String
  """
  The customer's sales order this money is for, when it arrives before the order is invoiced (a prepayment). Must be an order of the same customer.
  """
  salesOrderId: ID
}

"""A new customer."""
input CreateCustomerInput {
  """The city."""
  addressCity: String
  """The country."""
  addressCountry: String
  """The postal code."""
  addressPostalCode: String
  """The state or region."""
  addressState: String
  """The first line of the street address."""
  addressStreet1: String
  """The second line of the street address."""
  addressStreet2: String
  """True to also create the customer as a vendor, using the vendor terms."""
  alsoCreateAsVendor: Boolean! = false
  """
  The ID of the sales rep the customer is assigned to. Admins may set it. For a sales rep creating the customer, the server sets it to that rep.
  """
  assignedSalesRepId: String
  """The customer's business category."""
  businessCategory: String
  """How the customer buys."""
  buyingProcess: String
  """The customer's certifications."""
  certifications: [String!]
  """How the customer prefers to be contacted."""
  communicationPreference: String! = "EMAIL"
  """The size of the customer's company."""
  companySize: String
  """The email address of the main contact."""
  contactEmail: String
  """The name of the main contact."""
  contactName: String
  """The phone number of the main contact."""
  contactPhone: String
  """The credit limit. 0 or less means unlimited."""
  creditLimit: Int! = 0
  """The customer's credit rating."""
  creditRating: String
  """The customer's business type."""
  customerType: String
  """Who makes the buying decision."""
  decisionMaker: String
  """What the customer is."""
  description: String
  """The name to show for the customer."""
  displayName: String
  """The customer's industry."""
  industry: String
  """
  The vendor's expected days from order to delivery, when also created as a vendor.
  """
  leadTimeDays: Int
  """The legal name of the customer."""
  legalName: String
  """The customer's loyalty points."""
  loyaltyPoints: Int! = 0
  """The customer's loyalty tier."""
  loyaltyTier: String
  """True when the customer agreed to marketing messages."""
  marketingOptIn: Boolean! = true
  """The smallest order value the customer may place."""
  minimumOrderValue: Int
  """The name of the customer."""
  name: String!
  """Notes about the customer."""
  notes: String
  """The payment terms agreed with the customer."""
  paymentTerms: String
  """
  The currency of the customer's documents. Leave out to use the organization's default.
  """
  preferredCurrency: String
  """The customer's preferred shipping method."""
  preferredShippingMethod: String
  """The product categories the customer deals in."""
  productCategories: [String!]
  """The customer's company registration number."""
  registrationNumber: String
  """When the customer's buying peaks."""
  seasonality: String
  """The areas the customer serves."""
  serviceAreas: [String!]
  """Special instructions for handling the customer."""
  specialInstructions: String
  """Tags on the customer."""
  tags: [String!]! = []
  """The customer's tax ID."""
  taxId: String
  """The kind of customer."""
  type: String
  """The kind of vendor, when also created as a vendor."""
  vendorType: String
  """The customer's website."""
  website: String
}

"""A new debit note."""
input CreateDebitNoteInput {
  """A signed adjustment to the total, such as rounding. Defaults to 0."""
  adjustments: Float! = 0
  """The note amount before tax."""
  amount: Float!
  """The date the note is due."""
  dueDate: String
  """Notes for staff only."""
  internalNotes: String
  """The date the note is issued."""
  issueDate: String!
  """Notes shown on the note."""
  notes: String
  """The ID of the purchase invoice the note is raised against."""
  originalInvoiceId: String
  "The ID of the partner."
  partnerId: String!
  """The ID of the return the note comes from."""
  returnId: String
  """The tax on the note. Defaults to 0."""
  taxAmount: Float! = 0
  """
  What the note is for. Only supplier-side types are accepted, so SALES_RETURN is refused.
  """
  type: String!
}

"""One rule of a discount scheme."""
input CreateDiscountRuleDto {
  """What the rule is for."""
  description: String
  """How the discount is worked out: a percentage or a fixed amount."""
  discountType: DiscountCalculationType!
  """The percentage or the fixed amount."""
  discountValue: Float!
  "Whether the record is active."
  isActive: Boolean
  """The largest order amount the rule applies to."""
  maxAmount: Float
  """The most discount the rule may give."""
  maxDiscountAmount: Float
  """The largest quantity the rule applies to."""
  maxQuantity: Int
  """The smallest order amount the rule applies to."""
  minAmount: Float
  """The smallest quantity the rule applies to."""
  minQuantity: Int
  """The name of the rule."""
  name: String!
  """Which rule wins when several apply. Higher goes first."""
  priority: Int
}

"""A new discount scheme."""
input CreateDiscountSchemeDto {
  """The customer types the scheme applies to."""
  applicableCustomerTypes: String
  """The regions the scheme applies to."""
  applicableRegions: String
  """The code of the scheme."""
  code: String
  """
  The ID of the currency the scheme is for. Fixed amounts and order thresholds depend on the currency, so the scheme only applies to documents in it. Empty means the base currency.
  """
  currencyId: String
  """What the scheme is for."""
  description: String
  """The rules that set the discount."""
  discountRules: [CreateDiscountRuleDto!]!
  "Whether the record is active."
  isActive: Boolean
  """True when the scheme can combine with other discounts."""
  isStackable: Boolean
  """
  True when customers are put on the scheme automatically through customer tier settings instead of by hand. Only customer-scope schemes can be tier-managed.
  """
  isTierManaged: Boolean
  """The most times the scheme may be used in all."""
  maxUsageCount: Int
  """The most times one customer may use the scheme."""
  maxUsagePerCustomer: Int
  """The name of the scheme."""
  name: String!
  """Which scheme wins when several apply. Higher goes first."""
  priority: Int
  """
  What the scheme applies to: all customers, selected customers, products or categories.
  """
  scope: DiscountScope
  """When the scheme starts."""
  validFrom: String!
  """When the scheme ends."""
  validUntil: String
}

"""The organization's email settings, saved for the first time."""
input CreateEmailConfigInput {
  """The provider API key. It is write-only."""
  apiKey: String
  """The time of day the daily report is sent."""
  dailyReportTime: String
  """The addresses reports and alerts go to by default."""
  defaultRecipients: [String!]
  """The signature added to mail."""
  emailSignature: String
  """The address mail is sent from."""
  fromEmail: String!
  """The name mail is sent from."""
  fromName: String!
  """True when sending is switched on."""
  isEnabled: Boolean!
  """The day of the month the monthly report is sent."""
  monthlyReportDate: Int
  """
  The email provider: SMTP, SENDGRID, AWS_SES, MAILGUN, RESEND or GOOGLE.
  """
  provider: EmailProvider!
  """The address replies go to."""
  replyToEmail: String
  """True to send alert emails."""
  sendAlerts: Boolean! = true
  """True to send notification emails."""
  sendNotifications: Boolean! = true
  """True to send report emails."""
  sendReports: Boolean! = true
  """The SMTP server."""
  smtpHost: String
  """The SMTP password. It is write-only."""
  smtpPassword: String
  """The SMTP port."""
  smtpPort: Int
  """True to use a secure connection."""
  smtpSecure: Boolean
  """The SMTP user name."""
  smtpUser: String
  """The day of the week the weekly report is sent."""
  weeklyReportDay: Int
}

"""A new goods receipt."""
input CreateGRNInput {
  "ISO 4217 currency code."
  currency: String
  """True when damage was reported on delivery."""
  damageReported: Boolean! = false
  """The date the goods arrived. Defaults to now."""
  deliveryDate: String
  """The name of the driver who delivered the goods."""
  driverName: String
  """
  The rate to the organization's base currency: 1 unit of the receipt currency in the base currency. Needed when the currency is not the base currency.
  """
  exchangeRate: Float
  """The date the goods were expected."""
  expectedDate: String
  """When the goods were inspected."""
  inspectedAt: String
  """The ID of the user who inspected the goods."""
  inspectedBy: String
  """The lines received."""
  items: [CreateGRNItemInput!]!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes about the receipt."""
  notes: String
  """
  The date the purchase order was placed. Used to work out the actual lead time.
  """
  orderDate: String
  "The ID of the purchase order."
  purchaseOrderId: String
  """An overall quality score for the delivery."""
  qualityScore: Float
  """A reference to the delivery document, such as a delivery note number."""
  receiptDocument: String
  """True when a shortage was reported on delivery."""
  shortageReported: Boolean! = false
  """
  The receipt status, for example DRAFT, CONFIRMED, PARTIALLY_RECEIVED or RECEIVED.
  """
  status: String! = "RECEIVED"
  """The registration number of the delivery vehicle."""
  vehicleNumber: String
  """The ID of the vendor that delivered the goods."""
  vendorPartnerId: String!
  "The ID of the warehouse."
  warehouseId: String!
}

"""One line of a new goods receipt."""
input CreateGRNItemInput {
  """The quantity accepted after inspection. Only this goes into stock."""
  acceptedQuantity: Float!
  """The batch number of the stock."""
  batchNumber: String
  """How many damaged units were found. Defaults to 0."""
  damageCount: Int! = 0
  """How many defective units were found. Defaults to 0."""
  defectCount: Int! = 0
  """
  The discount carried from the purchase order line, in percent. Defaults to 0.
  """
  discountPercent: Float = 0
  """The date the stock expires."""
  expiryDate: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes about the line."""
  notes: String
  """The quantity ordered."""
  orderedQuantity: Float!
  "The ID of the product."
  productId: String!
  """The ID of the purchase order line the receipt line is against."""
  purchaseOrderItemId: String
  """The quality grade given to the line, for example A, B or C."""
  qualityGrade: String
  """The quantity that arrived."""
  receivedQuantity: Float!
  """The quantity rejected. Defaults to 0."""
  rejectedQuantity: Float! = 0
  """
  The tax rate carried from the purchase order line, in percent. Defaults to 0.
  """
  taxRate: Float = 0
  """The cost of one unit, in the receipt currency."""
  unitCost: Float!
  "The ID of the unit of measure."
  uomId: String
  "The ID of the product variant."
  variantId: String!
  """The ID of the vendor product the line is for."""
  vendorProductId: String
}

"""A new integration setting."""
input CreateIntegrationSettingInput {
  """The integration's configuration, as JSON."""
  config: JSON!
  """What the integration is for."""
  description: String
  """The name to show for the integration."""
  displayName: String!
  """True when the integration is switched on."""
  isEnabled: Boolean! = false
  """Which integration wins when several do the same job."""
  priority: Int! = 0
  """The service the integration is for."""
  serviceName: IntegrationService!
  """Tags on the integration."""
  tags: [String!]! = []
  """The version of the integration."""
  version: String! = "1.0"
  """The webhook address of the integration."""
  webhookUrl: String
}

"""
A return of goods from one warehouse to another inside the organization.
"""
input CreateInternalReturnInput {
  """The ID of the warehouse the goods leave."""
  fromWarehouseId: String!
  """The lines being returned."""
  items: [InternalReturnItemInput!]!
  """Why the goods are returned."""
  reason: String!
  """The ID of the warehouse the goods go to."""
  toWarehouseId: String!
  """The kind of internal transfer."""
  transferType: TransferType!
}

"""A new invoice."""
input CreateInvoiceInput {
  """Billing address, as JSON."""
  billingAddress: JSON
  """
  Invoicing a freight-quote sales order (too heavy to price delivery live) whose delivery charge is still unset is refused with DELIVERY_FREIGHT_CHARGE_UNSET. Send true to confirm the order ships with no delivery charge.
  """
  confirmZeroDeliveryCharge: Boolean
  """ISO 4217 currency code of the invoice."""
  currency: String
  """Additional invoice-level discount as an amount. Must not be negative."""
  discountAmount: Float
  """
  Payment due date, as an ISO 8601 date. When omitted it is the invoice date plus the payment term's days. A date you send is kept as a negotiated date.
  """
  dueDate: String
  """
  Exchange rate to the organization's base currency: 1 unit of the invoice currency equals this many base units. Must be greater than zero.
  """
  exchangeRate: Float
  """Notes for your team only, not shown to the customer."""
  internalNotes: String
  """The invoice date, as an ISO 8601 date."""
  invoiceDate: String!
  """Invoice number. A number is generated when omitted."""
  invoiceNumber: String
  """The invoice lines."""
  items: [InvoiceItemInput!]!
  """Notes shown to the customer on the invoice."""
  notes: String
  """
  The ID of the sales order this invoice bills. Must be an order in your organization. Without it the invoice is standalone and goes through the standalone credit check.
  """
  orderId: ID
  """The ID of the customer (sales invoice) or supplier (purchase invoice)."""
  partnerId: ID!
  """
  Payment terms code. Falls back to the customer's default, then the organization's default.
  """
  paymentTerms: String
  """Shipping address, as JSON."""
  shippingAddress: JSON
  """Shipping charge. Must not be negative."""
  shippingAmount: Float
  """Supplier code as it appeared when the invoice was created."""
  supplierCode: String
  """Supplier display name as it appeared when the invoice was created."""
  supplierDisplayName: String
  """Supplier email as it appeared when the invoice was created."""
  supplierEmail: String
  """Supplier name as it appeared when the invoice was created."""
  supplierName: String
  """Supplier phone as it appeared when the invoice was created."""
  supplierPhone: String
  """Surcharge. Must not be negative."""
  surchargeAmount: Float
  """Total tax on the invoice. Must not be negative."""
  taxAmount: Float
  """Whether prices include or exclude tax: INCLUSIVE or EXCLUSIVE."""
  taxCalculationMethod: String
  """
  Terms and conditions text printed on the invoice. Put the payment term code in paymentTerms, not here.
  """
  terms: String
  """
  SALES_INVOICE to bill a customer, PURCHASE_INVOICE to record a supplier bill.
  """
  type: InvoiceType!
  """The ID of the default warehouse for the invoice."""
  warehouseId: ID
}

"""A new language."""
input CreateLanguageInput {
  """The language code."""
  code: String!
  """The default date format."""
  dateFormat: String = "YYYY-MM-DD"
  """The writing direction: LTR or RTL."""
  direction: String = "LTR"
  "Whether the record is active."
  isActive: Boolean = true
  "Whether this is the default."
  isDefault: Boolean = false
  """The name of the language."""
  name: String!
  """The name of the language in that language."""
  nativeName: String!
  """The default time format."""
  timeFormat: String = "HH:mm:ss"
}

"""A new menu item."""
input CreateMenuInput {
  """What the menu item is for."""
  description: String
  """The icon of the menu item."""
  icon: String
  "Whether the record is active."
  isActive: Boolean!
  """True when the item is a main menu entry."""
  isMainMenu: Boolean!
  """The text shown for the menu item."""
  label: String!
  """MAIN or SUB."""
  menuType: MenuType!
  """The internal name of the menu item."""
  name: String!
  """The position among its siblings, lowest first."""
  order: Int!
  """The ID of the parent menu item."""
  parentId: String
  """The address the menu item opens."""
  path: String
  """The permissions needed to see the item."""
  requiredPermissions: [String!]
}

"""A new chat message."""
input CreateMessageInput {
  """The text of the message."""
  content: String!
  """The ID of the conversation."""
  conversationId: String!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The role of the sender."""
  role: String!
}

"""A new ordering address for the buyer."""
input CreateMobileAddressInput {
  """The first line of the address."""
  addressLine1: String!
  """The second line of the address."""
  addressLine2: String
  """
  Address classification (AddressType enum). Defaults to SHIPPING when omitted.
  """
  addressType: AddressType
  """The city."""
  city: String!
  """
  ISO-3166-1 alpha-2 country, sent by the client from TenantConfig.countryCode (no Qatar default).
  """
  country: String!
  """
  TRUE when the address serves BOTH the shipping and billing role. `addressType` stays the PRIMARY classification (one enum column cannot hold two roles) and this records the second — the same pair `myAddresses` already returns. Nullable/optional: app builds predating this field send nothing and the column defaults to false. Until this existed the buyer app had nowhere to put a both-ticked selection, so it encoded the combination in `name` ("Shipping & Billing") and parsed it back out on edit — do not go back to that.
  """
  isDualPurpose: Boolean
  """The latitude of the address on the map."""
  lat: Float
  """The longitude of the address on the map."""
  lng: Float
  """The name of the address."""
  name: String!
  """Phone in E.164 format, e.g. +97455551234."""
  phone: String!
  """
  Postal / ZIP code. OPTIONAL, unlike the admin address form which requires it: many of the countries this app ships to (QA, AE, …) have no postal system, and a required field there blocks the buyer from saving a perfectly valid address. Omitted or blank stores an empty string — `Address.postalCode` is a NOT NULL column, so it can never be null. Until this field existed the service wrote the literal "00000" for every mobile-created address, which is why older rows carry it.
  """
  postalCode: String
  """State / province / region. Falls back to city when omitted."""
  state: String
}

"""
The organization's tax configuration, for the first save and every later edit. Every field is optional and an omitted field keeps its saved value.
"""
input CreateOrganizationTaxConfigurationInput {
  """The ID of the tax group used for purchases when a product has none."""
  defaultPurchaseTaxGroupId: String
  """
  The ID of the tax group used for sales when a product has none. Null means a product must carry its own tax.
  """
  defaultSalesTaxGroupId: String
  """
  Whether prices include tax, exclude it, or compound it, when nothing else says.
  """
  defaultTaxCalculation: TaxCalculationMethod!
  """True to switch on e-way bill support."""
  enableEWayBill: Boolean
  """True to switch on GST compliance features."""
  enableGSTCompliance: Boolean
  """True to allow tax rules for more than one country."""
  enableMultiCountryTax: Boolean
  """True to let each product carry its own tax setup."""
  enableProductTaxMapping: Boolean
  """True to switch on tax alerts."""
  enableTaxAlerts: Boolean
  """True to keep an audit log of tax changes."""
  enableTaxAuditLog: Boolean
  """True to allow tax exemptions."""
  enableTaxExemption: Boolean
  """True to allow tax-inclusive pricing."""
  enableTaxInclusive: Boolean
  """True to switch on tax reporting."""
  enableTaxReporting: Boolean
  """The organization's GST registration number."""
  gstNumber: String
  """The state the organization is registered in for GST."""
  gstState: String
  """The organization's home currency code."""
  homeCurrency: String
  """How tax amounts are rounded."""
  taxRoundingMethod: String
  """How many decimal places tax amounts are rounded to."""
  taxRoundingPrecision: Int
  """The kind of tax system the organization uses."""
  taxSystemType: String!
}

"""A new partner: a customer, a vendor, or both."""
input CreatePartnerInput {
  """The partner's addresses."""
  addresses: [CreateAddressInput!]! = []
  """
  The ID of the sales rep the customer is assigned to. Only admins can change it.
  """
  assignedSalesRepId: String
  """The partner code. Leave out to generate one."""
  code: String
  """The partner's contacts."""
  contacts: [CreateContactInput!]! = []
  """The credit limit. 0 or less means unlimited."""
  creditLimit: Float = 0
  """The opening balance."""
  currentBalance: Float = 0
  """The partner's customer tier."""
  customerTier: String
  """What the partner is."""
  description: String
  """The standing discount, in percent."""
  discountPercent: Float = 0
  """The name to show for the partner."""
  displayName: String
  """The partner's industry."""
  industry: String
  """
  True when portal access is given separately, right after this create, so no login is made from the first email contact.
  """
  inviteSeparately: Boolean
  """The expected days from order to delivery."""
  leadTimeDays: Int = 0
  """The legal name of the partner."""
  legalName: String
  """The partner's loyalty points."""
  loyaltyPoints: Int = 0
  """The smallest order value."""
  minOrderValue: Float
  """The name of the partner."""
  name: String!
  """Notes about the partner."""
  notes: String
  """The payment terms agreed with the partner."""
  paymentTerms: String!
  """A rating of the partner."""
  rating: Float
  """The partner's company registration number."""
  registrationNumber: String
  """The roles of the partner, such as customer or supplier."""
  roles: [PartnerRole!]!
  """
  Which staff app the partner is created in, for example Admin Web or Sales App. It is shown in the pending approval queue.
  """
  source: String
  """The status of the partner."""
  status: PartnerStatus
  """Tags on the partner."""
  tags: [String!]! = []
  """The partner's tax ID."""
  taxId: String
  """The kind of partner."""
  type: PartnerType
  """The partner's website."""
  website: String
}

"""
Start an online payment checkout. Use orderId on retry to reuse an AWAITING_PAYMENT order.
"""
input CreatePaymentCheckoutInput {
  """
  Delivery address for a NEW order. Optional when orderId is supplied — a retry reuses the existing order's address (B5).
  """
  addressId: ID
  """
  the chosen live delivery option id (mobileDeliveryOptions). Required when the store prices delivery live; ignored otherwise.
  """
  deliveryOptionId: ID
  """
  Idempotency key — same key returns the same live checkout (no duplicate order).
  """
  idempotencyKey: String!
  """
  Ignored. The printed-invoice fee was removed; kept so existing app builds that send it keep working.
  """
  includePrintedInvoice: Boolean = false
  """
  Retry: reuse this AWAITING_PAYMENT order instead of creating a new one.
  """
  orderId: ID
  """
  Pay with this specific gateway — a `provider` value from mobilePaymentOptions. Validated server-side against the gateways eligible for the order's currency: an ineligible provider is rejected, never substituted. Omitted ⇒ the first eligible gateway (back-compat for shipped app builds).
  """
  provider: String
  """
  App deep link the payment browser returns to (e.g. provise://payment-return).
  """
  returnUrl: String!
  """The ID of the delivery slot the buyer picked."""
  slotId: ID
}

"""A payment or collection recorded against a customer or vendor."""
input CreatePaymentInput {
  """
  How the payment is split across invoices. Omit to leave it unallocated on account.
  """
  allocations: [PaymentAllocationInput!]
  """Payment amount, in currencyCode."""
  amount: Float!
  """The ID of the bank account the payment went through."""
  bankAccountId: ID
  """Cheque date, as an ISO 8601 date."""
  checkDate: String
  """Cheque number, for cheque payments."""
  checkNumber: String
  """ISO 4217 currency code of the payment."""
  currencyCode: String!
  """
  A unique key you generate, 8 to 128 characters. Retrying with the same key and the same payload returns the original payment; the same key with a different payload is refused.
  """
  idempotencyKey: String
  """The ID of the invoice this payment settles, if any."""
  invoiceId: ID
  """Notes about the payment."""
  notes: String
  """The ID of the customer or supplier."""
  partnerId: ID!
  """Date of the payment, as an ISO 8601 date."""
  paymentDate: String!
  """How the payment was made."""
  paymentMethod: PaymentMethod!
  """
  Your reference for the payment, such as a bank or transaction reference.
  """
  referenceNumber: String
  """
  COLLECTION for money received from a customer, PAYMENT for money paid to a supplier.
  """
  type: PaymentType!
}

"""A new payment term for the organization."""
input CreatePaymentTermInput {
  """
  Tenant-authored code, immutable once created because documents store it. Shape: an uppercase letter then A-Z/0-9/underscore, 2-32 chars (e.g. NET_7, EOM_30).
  """
  code: String!
  """Longer explanation of the term."""
  description: String
  """Whether the term can be chosen on new documents."""
  isActive: Boolean
  """
  Make this the organization's default term. The service clears any previous default in the same transaction.
  """
  isDefault: Boolean
  """NET (due after netDays), COD (cash on delivery) or PREPAID."""
  kind: PaymentTermKind!
  """Name shown when choosing the term."""
  label: String!
  """Number of days from the invoice date until payment is due."""
  netDays: Int!
  """Display order of the term in lists."""
  sortOrder: Int
}

"""A new attribute, with any first values."""
input CreateProductAttributeInput {
  """The attribute's name as admins see it."""
  name: String!
  """Values to define straight away."""
  values: [String!]
}

"""Starts a product import from a file."""
input CreateProductImportInput {
  """The name of the file."""
  filename: String!
  """
  The ID of a saved mapping profile to apply. Its field map overrides header detection. Optional.
  """
  mappingProfileId: String
  """Whether to only create new products or to update existing ones too."""
  mode: ProductImportMode = CREATE_ONLY
}

"""A started import and where to upload its file."""
type CreateProductImportResult {
  """The reference of the file to upload."""
  fileRef: String!
  """The ID of the import."""
  importId: String!
  """The URL to upload the file to."""
  uploadUrl: String!
}

"""A new product with its variants."""
input CreateProductInput {
  """The ID of the base unit of measure."""
  baseUOMId: ID
  "The ID of the brand."
  brandId: ID
  """The IDs of the categories the product is in."""
  categoryIds: [ID!]
  """What the product is."""
  description: String
  """The URLs of the product images."""
  imageUrls: [String!]! = []
  """The ID of the unit of measure stock is kept in."""
  inventoryUOMId: ID
  """True when the product is exempt from tax."""
  isTaxExempt: Boolean = false
  """The name of the product."""
  name: String!
  """The ID of the main category."""
  primaryCategoryId: ID
  """
  The tax group used when buying the product, on purchase orders and supplier bills. An empty string clears it.
  """
  purchaseTaxGroupId: String
  """The ID of the unit of measure used for purchases."""
  purchaseUOMId: ID
  """The ID of the unit of measure used for sales."""
  salesUOMId: ID
  """The status of the product."""
  status: ProductStatus! = ACTIVE
  """Tags on the product."""
  tags: [String!]! = []
  """Why the product is exempt from tax."""
  taxExemptReason: String
  "The ID of the tax group."
  taxGroupId: String
  """
  The IDs of the tax rates on the product, as one comma-separated string.
  """
  taxRateId: String
  """The variants of the product."""
  variants: [CreateProductVariantInput!]
}

"""A unit (pack) to add to a product or variant."""
input CreateProductUOMInput {
  """Barcode of this pack."""
  barcode: String
  """
  How many base units one of this unit contains. Must be greater than zero.
  """
  conversionFactor: Float! = 1
  """Global Trade Item Number (GTIN) of this pack."""
  gtin: String
  """Height of one of this unit. Must not be negative."""
  height: Float
  """
  Mark this as the product's base unit. Only the product's own base unit can be marked base.
  """
  isBase: Boolean! = false
  """Whether stock is held in this unit."""
  isInventory: Boolean! = false
  """Whether the unit can be used on purchase documents."""
  isPurchase: Boolean! = false
  """
  Whether the unit can be used on sales documents. A variant can have at most 3 sellable units.
  """
  isSales: Boolean! = false
  """Length of one of this unit. Must not be negative."""
  length: Float
  """List price of one of this unit. Must not be negative."""
  listPrice: Float
  """Null/unset = unlimited for this UOM tier."""
  maxOrderQty: Float
  """
  Smallest quantity of this unit that can be ordered. Must not be negative.
  """
  minOrderQty: Float! = 1
  """
  Quantities of this unit are ordered in multiples of this. Must be greater than zero.
  """
  orderMultiple: Float! = 1
  """The ID of the product to add the unit to."""
  productId: String!
  """Sale price of one of this unit. Must not be negative."""
  salePrice: Float
  """Standard cost of one of this unit. Must not be negative."""
  standardCost: Float
  """The ID of the unit of measure."""
  uomId: String!
  """
  The ID of the variant to add the unit to. Omit for a product-wide unit.
  """
  variantId: String
  """Weight of one of this unit. Must not be negative."""
  weight: Float
  """Width of one of this unit. Must not be negative."""
  width: Float
}

"""A new variant of a product."""
input CreateProductVariantInput {
  """The QR code of the variant."""
  QRCode: String
  """The variant's attributes, such as colour or size, as JSON."""
  attributes: JSON
  """The barcode of the variant."""
  barcode: String
  """The ID of the base unit of measure."""
  baseUOMId: ID
  """The cost of one unit."""
  cost: Float
  """The size of one unit, as JSON."""
  dimensions: JSON
  """The URL of the main image."""
  imageUrl: String
  """The URLs of the images."""
  imageUrls: [String!]
  """The ID of the unit of measure stock is kept in."""
  inventoryUOMId: ID
  "Whether the record is active."
  isActive: Boolean! = true
  "Whether this is the default."
  isDefault: Boolean
  """The largest quantity that can be ordered."""
  maxOrderQuantity: Float
  """The page description for search engines."""
  metaDescription: String
  """The page title for search engines."""
  metaTitle: String
  """The smallest quantity that can be ordered."""
  minOrderQuantity: Float! = 1
  """The name of the variant."""
  name: String
  """Opening stock quantity to be added to inventory"""
  openingStock: Float
  """Batch number for opening stock"""
  openingStockBatchNumber: String
  """Cost per unit for opening stock"""
  openingStockCost: Float
  """
  The packs sold with the variant. They are saved before the price tiers, which are checked against them.
  """
  packs: [CreateVariantPackInput!]
  """The list price. Must be greater than zero."""
  price: Float
  """The ID of the unit of measure used for purchases."""
  purchaseUOMId: ID
  """Pre-negotiated sale price"""
  salePrice: Float
  """The ID of the unit of measure used for sales."""
  salesUOMId: ID
  """The serial number of the variant."""
  serialNo: String
  """The SKU of the variant."""
  sku: String
  """Tags on the variant."""
  tags: [String!]
  """The price tiers, by quantity and customer tier."""
  variantPrices: [CreateVariantPriceInput!]
  """Warehouse ID for opening stock"""
  warehouseId: ID
  """The weight of one unit."""
  weight: Float
}

"""Input to create a purchase order."""
input CreatePurchaseOrderInput {
  """
  Alternative tax rate applied to the order, when it differs from the per-line rates.
  """
  alternativeTaxRate: String
  """Cost tier the supplier prices were taken from."""
  costTier: String
  """Address the supplier delivers to, as a JSON address object."""
  deliveryAddress: JSON
  """Free-text delivery instructions for the supplier."""
  deliveryInstructions: String
  """Order-level discount, in the order currency."""
  discountAmount: Float! = 0
  """
  Exchange rate between the order currency and the organization's base currency.
  """
  exchangeRate: Float! = 1
  """Date the goods are expected to arrive."""
  expectedDate: DateTime
  """Freight charge for the order, in the order currency."""
  freightAmount: Float! = 0
  """Comments for your team only; never shown to the supplier."""
  internalComments: String
  """The lines on the order."""
  items: [CreatePurchaseOrderItemInput!]!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes on the order, visible to the supplier."""
  notes: String
  """Currency code of the order's amounts."""
  orderCurrency: String
  """Date the order was placed."""
  orderDate: String
  """Payment terms agreed with the supplier."""
  paymentTerms: String!
  """Project the purchase is for, if any."""
  projectName: String
  """The ID of the user who received the goods."""
  receivedBy: String
  """
  Address the order is shipped from or billed to, as a JSON address object.
  """
  shippingAddress: JSON
  """Shipping charge for the order, in the order currency."""
  shippingAmount: Float! = 0
  """The ID of the sales order this purchase order is raised for, if any."""
  sourceSalesOrderId: String
  """The supplier's code."""
  supplierCode: String
  """The supplier's display name."""
  supplierDisplayName: String
  """The supplier's email address."""
  supplierEmail: String
  "The ID of the supplier."
  supplierId: String!
  """The supplier's legal name."""
  supplierName: String
  """The supplier's phone number."""
  supplierPhone: String
  """Surcharge on the order, in the order currency."""
  surchargeAmount: Float! = 0
  """Carrier tracking code for the shipment."""
  trackingCode: String
  "The ID of the warehouse."
  warehouseId: String
}

"""A line on a purchase order being created."""
input CreatePurchaseOrderItemInput {
  """Discount on this line, as a percentage."""
  discountPercent: Float! = 0
  """The ID of the unit of measure the line is stocked in."""
  inventoryUOMId: String
  """Notes on this line."""
  notes: String
  "The ID of the product."
  productId: String!
  """Quantity ordered, in the line's unit of measure."""
  quantity: Float!
  """Shipping charge allocated to this line."""
  shippingAmount: Float! = 0
  """Surcharge allocated to this line."""
  surchargeAmount: Float! = 0
  "The ID of the tax group."
  taxGroupId: String
  """Tax rate on this line, as a percentage."""
  taxRate: Float! = 0
  """The IDs of the tax rates applied to this line."""
  taxRateIds: [String!]
  """Price per unit, in the order currency."""
  unitPrice: Float!
  "The ID of the unit of measure."
  uomId: String!
  "The ID of the product variant."
  variantId: String
}

"""A return of goods to a vendor."""
input CreatePurchaseReturnInput {
  """The ID of the goods receipt the return is against."""
  grnId: String
  """The lines being returned."""
  items: [PurchaseReturnItemInput!]!
  "The ID of the purchase order."
  purchaseOrderId: String
  """
  Why the goods are returned: DAMAGED, INCORRECT, DEFECTIVE, EXPIRED, NOT_REQUIRED or OTHER.
  """
  reason: String!
  """True when the return needs approval before it goes ahead."""
  requiresApproval: Boolean
  """How the goods are sent back."""
  shippingMethod: String
  "The ID of the supplier."
  supplierId: String!
  "The ID of the warehouse."
  warehouseId: String!
}

"""Input to create a quote for a customer."""
input CreateQuoteInput {
  """Billing address shown on the quote."""
  billingAddress: String
  """
  Opt in to pricing a foreign-currency line with no price in the quote currency by converting its base price at exchangeRate. Without it such a line is refused. A price in the quote currency always wins.
  """
  convertMissingCurrencyPrices: Boolean
  """ISO 4217 currency code of the quote."""
  currency: String!
  """
  Email address the quote is addressed to. It can differ from the customer's main email.
  """
  customerEmail: String
  """The ID of the customer the quote is for."""
  customerId: String!
  """Customer mobile number shown on the quote."""
  customerMobile: String
  """Customer name shown on the quote."""
  customerName: String
  """Delivery instructions for this quote."""
  deliveryInstructions: String
  """Quote-level discount as an amount. Must not be negative."""
  discountAmount: Float!
  """How the quote-level discount is read: PERCENTAGE or AMOUNT."""
  discountType: String!
  """
  Quote-level discount, read as a percentage or an amount according to discountType. Must not be negative.
  """
  discountValue: Float!
  """
  Exchange rate between the quote currency and the organization's base currency. Must be greater than zero.
  """
  exchangeRate: Float
  """
  Idempotency key: retries with the same key + identical payload replay the original quote.
  """
  idempotencyKey: String
  """Notes for your team only, not shown to the customer."""
  internalNotes: String
  """The quote lines. At least one line is required."""
  items: [CreateQuoteItemInput!]!
  """Notes for the customer."""
  notes: String
  """The user who owns the quote."""
  ownership: DocumentOwnershipInput
  """Payment terms code. It must be a valid payment term code."""
  paymentTerms: String
  """Priority of the quote: LOW, NORMAL, HIGH or URGENT."""
  priority: String
  """
  The quote's date, as an ISO 8601 date. Empty means today. Any other date needs the backdate permission and is recorded in the audit trail.
  """
  quoteDate: String
  """Reference shown on the quote, such as a customer enquiry number."""
  reference: String
  """Shipping address shown on the quote."""
  shippingAddress: String
  """Shipping cost for the quote. Must not be negative."""
  shippingCost: Float!
  """
  Initial status. A quote cannot be created already decided, so ACCEPTED, REJECTED, EXPIRED, CONVERTED and CANCELLED are refused. Defaults to DRAFT.
  """
  status: String
  """Sum of the line values before quote-level discount, tax and shipping."""
  subtotal: Float!
  """Total tax on the quote."""
  taxAmount: Float!
  """Tax method for the whole quote: INCLUSIVE or EXCLUSIVE."""
  taxCalculationMethod: String
  """Quote-level tax rate."""
  taxRate: Float!
  """Terms and conditions text for the quote."""
  terms: String
  """Total amount of the quote."""
  totalAmount: Float!
  """Date the quote stops being valid, as an ISO 8601 date."""
  validUntil: String
  """The ID of the default warehouse for the quote."""
  warehouseId: String
}

"""A line on a quote being created."""
input CreateQuoteItemInput {
  """
  Whether the buyer accepts a substitute if this item is unavailable. Carried to the sales order line on conversion.
  """
  acceptAlternativeIfUnavailable: Boolean
  """Free-text note shown on the quote line."""
  description: String
  """
  Line discount, read as a percentage or an amount according to discountType. Must not be negative; a percentage cannot exceed 100.
  """
  discount: Float!
  """Line discount as an amount. Must not be negative."""
  discountAmount: Float
  """How discount is read: PERCENTAGE or AMOUNT."""
  discountType: String!
  """Why the price was overridden. Up to 500 characters."""
  overrideReason: String
  """
  Set to true to keep a negotiated unitPrice instead of the catalogue price. The caller needs the quote price-override permission.
  """
  priceOverride: Boolean
  """The ID of the product being quoted."""
  productId: String!
  """Product name shown on the quote line."""
  productName: String!
  """SKU shown on the quote line."""
  productSku: String
  """
  Quantity quoted, in the unit given by uomId. Must be greater than zero.
  """
  quantity: Float!
  """Pre-negotiated sale price from variant"""
  salePrice: Float
  """Tax amount for the line."""
  taxAmount: Float!
  """Tax split by component, as JSON."""
  taxBreakdown: JSON
  """
  Whether the line price includes or excludes tax: INCLUSIVE or EXCLUSIVE.
  """
  taxCalculationMethod: String
  """Tax rate applied to the line."""
  taxRate: Float!
  """Total for the line."""
  totalPrice: Float
  """Price per unit in the quote currency. Must not be negative."""
  unitPrice: Float!
  """The ID of the unit of measure for the quantity."""
  uomId: String
  """Name of the unit of measure, shown on the line."""
  uomName: String
  """The ID of the product variant being quoted."""
  variantId: String!
  """The ID of the warehouse that supplies this line."""
  warehouseId: String
}

"""A new region."""
input CreateRegionInput {
  """The name of the city."""
  cityName: String
  """The region code."""
  code: String!
  """The country code."""
  countryCode: String
  "Whether the record is active."
  isActive: Boolean! = true
  """The name of the region."""
  name: String!
  """The pattern postal codes follow."""
  postalCodePattern: String
  """The state code."""
  stateCode: String
  """The time zone of the region."""
  timezone: String
}

"""
A new return against a sales or purchase order. Only SALES_RETURN and PURCHASE_RETURN are accepted here.
"""
input CreateReturnInput {
  """
  The ID of the goods receipt the return is against, for a purchase return.
  """
  grnId: String
  """The lines being returned."""
  items: [ReturnItemInput!]!
  """Notes about the return."""
  notes: String
  """The ID of the order the goods came from."""
  originalOrderId: String!
  """Why the goods are returned."""
  reason: ReturnReason!
  """Free-text detail on the reason."""
  reasonDescription: String
  """The date of the return."""
  returnDate: DateTime
  """The kind of return."""
  type: ReturnType!
  "The ID of the warehouse."
  warehouseId: String!
}

"""A new role."""
input CreateRoleInput {
  """What the role is for."""
  description: String
  """The name to show for the role."""
  displayName: String!
  "Whether the record is active."
  isActive: Boolean
  """Extra information about the role, as JSON text."""
  metadata: String
  """The name of the role."""
  name: String!
  """The rank of the role."""
  priority: Int
}

"""A new SKU pattern."""
input CreateSKUPatternInput {
  "The ID of the brand."
  brandId: String
  "The ID of the category."
  categoryId: String
  """What the pattern is for."""
  description: String
  """An example of a generated SKU."""
  example: String
  "Whether the record is active."
  isActive: Boolean! = true
  """The name of the pattern."""
  name: String!
  """The pattern, using placeholders such as {BRAND}-{CATEGORY}-{SEQ}."""
  pattern: String!
  """Which pattern wins when several match. Defaults to 1."""
  priority: Int! = 1
  """How many digits the running number has. Defaults to 4."""
  sequenceLength: Int! = 4
}

"""A postal address on a sales order being created."""
input CreateSalesOrderAddressInput {
  """City."""
  city: String!
  """Country."""
  country: String!
  """
  The ID of the saved address this one was copied from, if any. It is for matching the order back to that address and does not change pricing or tax.
  """
  id: String
  """
  Whether the saved address this one was copied from serves as both billing and shipping.
  """
  isDualPurpose: Boolean
  """Label of the saved address this one was copied from, if any."""
  label: String
  """Postal or ZIP code."""
  postalCode: String!
  """State or region."""
  state: String!
  """First line of the street address."""
  street1: String!
  """Second line of the street address."""
  street2: String
  """Type of the saved address this one was copied from, if any."""
  type: String
}

"""Input to create a sales order."""
input CreateSalesOrderInput {
  """Billing address for the order."""
  billingAddress: CreateSalesOrderAddressInput
  """
  Branch attribution: the branch Address id this order was placed for. Written at create only.
  """
  branchAddressId: String
  """
  Opt in to pricing a foreign-currency line with no price in the order currency by converting its base price at exchangeRate. Without it such a line is refused. A price in the order currency always wins.
  """
  convertMissingCurrencyPrices: Boolean
  """ISO 4217 currency code of the order."""
  currency: String
  """Customer email shown on the order."""
  customerEmail: String
  """The ID of the customer the order is for."""
  customerId: String!
  """Customer mobile number shown on the order."""
  customerMobile: String
  """Buyer-supplied PO number, persisted to SalesOrder.customerPoNumber."""
  customerPoNumber: String
  """Delivery instructions for the order."""
  deliveryInstructions: String
  """
  A staff delivery option id from staffDeliveryOptions. The server sets shippingAmount (the quoted fee, no tax added), the ship-to address and the delivery choice from it; the client shippingAmount is ignored.
  """
  deliveryOptionId: ID
  """Additional order-level discount as an amount. Must not be negative."""
  discountAmount: Float! = 0
  """The ID of the discount scheme to apply to the order."""
  discountSchemeId: String
  """
  Exchange rate between the order currency and the organization's base currency. Must be greater than zero.
  """
  exchangeRate: Float
  """
  A unique key you generate. Retrying with the same key returns the original order instead of creating a duplicate.
  """
  idempotencyKey: String
  """Notes for your team only, not shown to the customer."""
  internalNotes: String
  """The order lines."""
  items: [CreateSalesOrderItemInput!]!
  """Notes for the customer."""
  notes: String
  """
  The order's date, as an ISO 8601 date. Empty means today. Any other date needs the backdate permission and is recorded in the audit trail.
  """
  orderDate: String
  """
  The payment method the buyer chose at checkout (e.g. EFT, ON_ACCOUNT, GATEWAY, COD). Display attribution only — persisted to metadata.paymentMethod; paymentTerms stays the behavioural signal.
  """
  paymentMethod: String
  """Payment terms code for the order."""
  paymentTerms: String!
  """Date the order is promised for delivery."""
  promisedDate: DateTime
  """Reference shown on the order."""
  reference: String
  """Shipping address for the order."""
  shippingAddress: CreateSalesOrderAddressInput
  """Shipping charge for the order."""
  shippingAmount: Float! = 0
  """Shipping method for the order."""
  shippingMethod: String
  """Tax on the shipping/delivery fee, added to header taxAmount."""
  shippingTaxAmount: Float
  """
  Initial status: DRAFT (no inventory reserved) or CONFIRMED (reserves inventory). Defaults to DRAFT.
  """
  status: SalesOrderStatus
  """Whether prices include or exclude tax: INCLUSIVE or EXCLUSIVE."""
  taxCalculationMethod: String
  """The ID of the default warehouse for the order."""
  warehouseId: String
}

"""A line on a sales order being created."""
input CreateSalesOrderItemInput {
  """Whether the buyer accepts a substitute if this item is unavailable."""
  acceptAlternativeIfUnavailable: Boolean
  """Line discount as a percentage, from 0 to 100."""
  discountPercent: Float! = 0
  """
  The ID of the inventory unit of measure, used to convert the ordered quantity into stock units.
  """
  inventoryUOMId: String
  """Note shown on the order line."""
  notes: String
  """Why the price was overridden."""
  overrideReason: String
  """
  Set to true to keep your unitPrice instead of the resolved price. Needs the line price-override permission when pricing authority is enforced.
  """
  priceOverride: Boolean
  """
  The ID of the product. The variant decides the product, so this is accepted but the variant wins.
  """
  productId: String!
  """
  Quantity ordered, in the unit given by uomId. Must be greater than zero.
  """
  quantity: Float!
  """Tax amount for the line."""
  taxAmount: Float! = 0
  """Tax split by component, as JSON."""
  taxBreakdown: JSON
  """The ID of the tax group that decides the line's tax rates."""
  taxGroupId: String
  """Tax rate applied to the line."""
  taxRate: Float! = 0
  """The IDs of the tax rates to apply to the line."""
  taxRateIds: [String!]
  """
  Price per unit. Optional: when omitted the server resolves the price itself.
  """
  unitPrice: Float
  """The ID of the unit of measure for the quantity."""
  uomId: String!
  """The ID of the product variant being ordered."""
  variantId: String!
  """The ID of the warehouse that supplies this line."""
  warehouseId: String
}

"""A return of goods from a customer, against an invoice."""
input CreateSalesReturnInput {
  "The ID of the customer."
  customerId: String!
  """True when the customer asked for the return."""
  customerRequest: Boolean
  "The ID of the invoice."
  invoiceId: String!
  """The lines being returned."""
  items: [SalesReturnItemInput!]!
  """Where to collect the goods."""
  pickupAddress: String
  """
  Why the goods are returned: DAMAGED, INCORRECT, DEFECTIVE, EXPIRED, NOT_REQUIRED or OTHER.
  """
  reason: String!
  """How the customer is compensated."""
  refundMethod: RefundMethod!
  """True when the goods need collecting from the customer."""
  requiresPickup: Boolean
  "The ID of the warehouse."
  warehouseId: String!
}

"""A new short link."""
input CreateShortUrlInput {
  """A custom short code to use instead of a generated one."""
  customAlias: String
  """What the link is for."""
  description: String
  """When the link stops working."""
  expiresAt: DateTime
  """The address the short link leads to."""
  originalUrl: String!
  """Tags on the link."""
  tags: [String!]
  """A title for the link."""
  title: String
}

"""A new stock movement."""
input CreateStockMovementInput {
  """The batch number of the stock."""
  batchNumber: String
  """The ID of the warehouse the stock leaves."""
  fromWarehouseId: ID
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes about the movement."""
  notes: String
  "The ID of the product."
  productId: ID!
  """The quantity to move."""
  quantity: Float!
  """Why the movement is made."""
  reason: String
  """The ID of that document."""
  referenceId: String
  """The kind of document that causes the movement."""
  referenceType: String
  """The serial number of the stock."""
  serialNumber: String
  """The ID of the warehouse the stock goes to."""
  toWarehouseId: ID
  """The kind of movement."""
  type: MovementType!
  "The ID of the unit of measure."
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
}

"""A payment made to a vendor."""
input CreateSupplierPaymentInput {
  """
  The supplier invoices to allocate the payment to and the amount for each.
  """
  allocations: [PaymentAllocationInput!]
  """Payment amount, in the payment currency. Must be greater than zero."""
  amount: Float!
  """Attachments to record on the payment, as strings."""
  attachments: [String!]
  """The ID of the bank account the payment went through."""
  bankAccountId: ID
  """Cheque date."""
  checkDate: DateTime
  """Cheque number, for cheque payments."""
  checkNumber: String
  """ISO 4217 currency code of the payment."""
  currency: String!
  """
  Exchange rate to the organization's base currency. Must be greater than zero.
  """
  exchangeRate: Float
  """
  A unique key you generate, 8 to 128 characters. Retrying with the same key returns the original payment.
  """
  idempotencyKey: String
  """Notes for your team only."""
  internalNotes: String
  """Notes about the payment."""
  notes: String
  """Date of the payment."""
  paymentDate: DateTime!
  """How the payment was made."""
  paymentMethod: PaymentMethod!
  """
  Your reference for the payment, such as a bank or transaction reference.
  """
  referenceNumber: String
  """The ID of the supplier being paid."""
  supplierId: ID!
  """Transaction identifier from the bank or gateway."""
  transactionId: String
}

"""A new tax group: a set of tax rates applied together."""
input CreateTaxGroupInput {
  """How the rates in the group combine."""
  calculationMethod: TaxCalculationMethod!
  """The code of the group."""
  code: String!
  """What the group is for."""
  description: String
  "Whether the record is active."
  isActive: Boolean! = true
  """The name of the group."""
  name: String!
  """The IDs of the tax rates in the group."""
  taxRateIds: [String!]!
}

"""A new tax rate."""
input CreateTaxRateInput {
  """The product categories the tax applies to."""
  applicableProductCategories: [String!]
  """How the tax is worked out against the price."""
  calculationMethod: TaxCalculationMethod!
  """The city the tax applies in."""
  city: String
  """The code of the tax rate."""
  code: String!
  """The country the tax applies in."""
  country: String!
  """What the tax rate is for."""
  description: String
  """The product categories the tax does not apply to."""
  exemptProductCategories: [String!]
  "Whether the record is active."
  isActive: Boolean! = true
  "Whether this is the default."
  isDefault: Boolean! = false
  """The level the tax applies at: federal, state, county, city or custom."""
  jurisdiction: TaxJurisdiction!
  """The largest amount the tax applies to."""
  maximumAmount: Float
  """The smallest amount the tax applies to."""
  minimumAmount: Float
  """The name of the tax rate."""
  name: String!
  """The postal code the tax applies in."""
  postalCode: String
  """The rate, in percent."""
  rate: Float!
  """The state or region the tax applies in."""
  state: String
  """The kind of tax."""
  type: TaxType!
  """When the tax starts to apply."""
  validFrom: DateTime
  """When the tax stops applying."""
  validTo: DateTime
}

"""
Adds one of the organization's own dated exchange rates, from a foreign currency to the base currency.
"""
input CreateTenantExchangeRateInput {
  """
  First calendar day the rate applies (YYYY-MM-DD), from 00:00 on the organization's clock; never before today
  """
  effectiveFrom: String!
  """
  Stop day (YYYY-MM-DD, exclusive): the rate stops at 00:00 of this day on the organization's clock
  """
  effectiveTo: String
  """ISO code of one of the org's currencies (not the base)"""
  fromCurrency: String!
  """A note on why the rate was set."""
  note: String
  """1 fromCurrency = rate base currency, as an exact decimal"""
  rate: String!
}

"""A new setting."""
input CreateTenantSettingInput {
  """The group the setting is in."""
  category: SettingCategory!
  """The data type of the value."""
  dataType: SettingDataType! = STRING
  """What the setting does."""
  description: String
  "Whether the record is active."
  isActive: Boolean! = true
  """The key of the setting."""
  key: String!
  """A rule the value must follow."""
  validationRule: String
  """The value."""
  value: JSON
}

"""A new time zone."""
input CreateTimezoneInput {
  """The short name, for example GMT."""
  abbreviation: String
  """The IANA time zone code, for example Europe/London."""
  code: String!
  """A description of the time zone."""
  description: String
  """When daylight saving time ends."""
  dstEnd: String
  """The offset during daylight saving time."""
  dstOffset: String
  """When daylight saving time starts."""
  dstStart: String
  """True when it observes daylight saving time."""
  dstSupported: Boolean! = false
  "Whether the record is active."
  isActive: Boolean! = true
  "Whether this is the default."
  isDefault: Boolean! = false
  """The name of the time zone."""
  name: String!
  """The offset from UTC."""
  offset: String!
  """The regions it covers."""
  regions: [String!]
  """The position in lists, lowest first."""
  sortOrder: Int! = 0
}

"""A conversion to create between two units of the same category."""
input CreateUOMConversionInput {
  """
  Multiply a quantity in the from unit by this to get the quantity in the to unit. The reverse conversion uses 1 divided by it.
  """
  conversionFactor: Float!
  """Optional formula text to record for the conversion."""
  formula: String
  """The ID of the unit to convert from."""
  fromUOMId: String!
  """
  The ID of the unit to convert to. It must be in the same category as the from unit.
  """
  toUOMId: String!
}

"""A new unit of measure."""
input CreateUOMInput {
  """
  Whether quantities in this unit may be fractional. Must be false for a COUNT unit.
  """
  allowFractional: Boolean! = false
  """
  The kind of quantity the unit measures. Units convert only within a category.
  """
  category: UOMCategory!
  """
  Short code that identifies the unit. It must be unique in the organization, ignoring case. At most 20 characters.
  """
  code: String!
  """Colour code used to show the unit."""
  colorCode: String
  """The ID of the unit this unit combines with in compound quantities."""
  compoundWithUOMId: String
  """
  How many decimal places quantities in this unit show, from 0 to 6. Must be 0 for a COUNT unit.
  """
  decimalPlaces: Int! = 0
  """Free-text description of the unit."""
  description: String
  """Position of the unit in lists. Lower numbers come first."""
  displayOrder: Int! = 0
  """URL of the unit's icon image."""
  iconUrl: String
  """
  Make this the base unit of its category. It clears the flag from the category's current base unit.
  """
  isBase: Boolean! = false
  """The unit's name. At most 100 characters."""
  name: String!
  """Plural form of the name, when it needs one."""
  pluralName: String
  """Symbol shown next to quantities in this unit. At most 20 characters."""
  symbol: String!
}

"""A new user."""
input CreateUserInput {
  """The URL of the user's picture."""
  avatar: String
  "Email address."
  email: String!
  """The user's first name."""
  firstName: String!
  """The user's job title."""
  jobRole: String
  """The user's last name."""
  lastName: String!
  """The ID of the organization the user belongs to."""
  organizationId: String
  "Phone number."
  phone: String
  """The user's role."""
  role: UserRole
  "The ID of the role."
  roleId: String
  """The status of the user."""
  status: UserStatus
}

"""A new reporting or other relationship between two users."""
input CreateUserRelationshipInput {
  """Optional notes about this relationship"""
  notes: String
  """User ID of the supervisor/manager"""
  relatedUserId: String!
  """Type of relationship"""
  relationshipType: UserRelationshipType!
  """User ID of the subordinate"""
  userId: String!
}

"""
A sellable pack, for example 1 case of 12, created together with its variant.
"""
input CreateVariantPackInput {
  """How many base units the pack holds"""
  conversionFactor: Float!
  """
  How many units one pack holds. Orders in this pack are a multiple of it.
  """
  orderMultiple: Float
  "The ID of the unit of measure."
  uomId: ID!
}

"""A price tier on a variant."""
input CreateVariantPriceInput {
  """The cost of one unit in the tier."""
  cost: Float
  "ISO 4217 currency code."
  currency: String
  """The customer tiers the price is for."""
  customerTierIds: [String!]
  """The discount in percent. Defaults to 0."""
  discountPercent: Float! = 0
  "Whether the record is active."
  isActive: Boolean! = true
  """The largest quantity the tier applies to."""
  maxQuantity: Float
  """The smallest quantity the tier applies to."""
  minQuantity: Float!
  """The name of the tier."""
  name: String!
  """
  The price in the tier. 0 is a deliberate free tier, and a negative price is never valid.
  """
  price: Float!
  "The ID of the unit of measure."
  uomId: String
  """When the tier starts to apply."""
  validFrom: String
  """When the tier stops applying."""
  validTo: String
}

"""A product variant a vendor supplies."""
input CreateVendorProductInput {
  """The credit limit the vendor gives."""
  creditAmount: Float! = 0
  """The days of credit the vendor gives."""
  creditDays: Int! = 0
  "ISO 4217 currency code."
  currency: String
  """A rating of the vendor's delivery performance."""
  deliveryRating: Float
  "Whether the record is active."
  isActive: Boolean! = true
  """True when this is a preferred vendor for the product."""
  isPreferred: Boolean! = false
  """The expected days from order to delivery."""
  leadTimeDays: Int! = 0
  """The largest quantity the vendor will supply per order."""
  maxOrderQuantity: Float
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The smallest quantity the vendor will supply per order."""
  minOrderQuantity: Float! = 1
  """Notes about the vendor product."""
  notes: String
  """Orders must be a multiple of this quantity."""
  orderMultiple: Float! = 1
  "The ID of the product."
  productId: String!
  """A rating of the quality of the vendor's goods."""
  qualityRating: Float
  """The agreed standard cost of one unit."""
  standardCost: Float
  "The ID of the product variant."
  variantId: String!
  """The brand the vendor sells the product under."""
  vendorBrand: String
  """The vendor's own name for the product."""
  vendorName: String
  """The ID of the vendor."""
  vendorPartnerId: String!
  """The vendor's own code for the product."""
  vendorSku: String!
}

"""A new warehouse."""
input CreateWarehouseInput {
  """
  The address as JSON: street1, street2, city, state, country, postalCode, and optionally latitude and longitude.
  """
  address: JSON
  """The storage capacity of the warehouse."""
  capacity: Int
  """The warehouse code, unique within the organization."""
  code: String!
  """The contact email address."""
  contactEmail: String
  """The contact phone number."""
  contactPhone: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The warehouse name."""
  name: String!
  """
  The tax registration number of this location. When blank, the organization's number is used on the documents the warehouse issues.
  """
  taxRegistrationNumber: String
  """The kind of warehouse, such as main, branch or distribution."""
  type: String!
}

"""A return of goods under warranty."""
input CreateWarrantyReturnInput {
  "The ID of the customer."
  customerId: String!
  "The ID of the invoice."
  invoiceId: String!
  """The lines being returned."""
  items: [WarrantyReturnItemInput!]!
  """The service provider who handles the claim."""
  serviceProvider: String
  "The ID of the warehouse."
  warehouseId: String!
  """The warranty claim number."""
  warrantyClaimNo: String!
}

"""
A new WhatsApp message template, with optional header, footer and buttons. It supports no header, a text header, or an image, video or document header, but no carousel.
"""
input CreateWhatsAppTemplateInput {
  """The text of the message, with {{1}}, {{2}} and so on for variables."""
  body: String!
  """Sample values for each placeholder in the body, in order."""
  bodyText: [String!]!
  """The buttons of the template."""
  buttons: [WhatsAppTemplateButtonInput!]!
  """Marketing, Utility or Authentication."""
  category: String!
  """The name of the template."""
  displayName: String!
  """The footer text."""
  footer: String
  """The kind of header: NONE, TEXT, IMAGE, VIDEO or DOCUMENT."""
  headerFormat: String
  """The URL of the header image, video or document."""
  headerMediaUrl: String
  """The header text. Required when the header format is TEXT."""
  headerText: String
  """
  The language name the provider uses, for example English, not the short ISO code.
  """
  language: String!
}

"""The user who created a record."""
type CreatedBy {
  """The name of the user."""
  name: String!
}

"""The user who created a record, resolved from the user ID saved on it."""
type CreatedByUser {
  "Email address."
  email: String
  """The user's first name."""
  firstName: String
  "The unique ID of this record."
  id: ID!
  """The user's last name."""
  lastName: String
  """
  The user's display role: the organization's role name, else the job title, else the legacy role. Empty when none applies.
  """
  role: String
}

"""
A credential field and its plaintext value. Only non-secret fields are returned.
"""
type CredentialValueGql {
  """The name of the credential field."""
  key: String!
  """The value of the credential field."""
  value: String!
}

"""A credential field and the value to store."""
input CredentialValueInput {
  """Name of the credential field."""
  key: String!
  """Value of the credential field."""
  value: String!
}

"""
A customer's credit exposure: what they owe, what is committed, and the headroom left under their credit limit.
"""
type CreditExposureResult {
  """
  Currency code the amounts are expressed in: the organization's base currency.
  """
  baseCurrency: String!
  """invoiceExposure + uninvoicedCommitment"""
  currentExposure: Float!
  """
  False when the org's credit-limit module is disabled — exposure figures above are still real (not zeroed), but no limit is enforced
  """
  enabled: Boolean!
  """limit - currentExposure; null when unlimited"""
  headroom: Float
  """Σ open invoice base outstanding"""
  invoiceExposure: Float!
  """Base-currency credit limit; 0 when unlimited/unset"""
  limit: Float!
  """SALES (customer A/R) or PURCHASE (vendor A/P)"""
  side: String!
  """Σ committed credit-terms order not-yet-invoiced base value"""
  uninvoicedCommitment: Float!
  """True when no positive limit is configured"""
  unlimited: Boolean!
}

"""
A credit note: money owed back to a customer, from a sales return, a price adjustment or goodwill.
"""
type CreditNote {
  """How much of the note has been applied to invoices."""
  appliedAmount: Float!
  "When the record was created."
  createdAt: DateTime!
  """The user who created the note."""
  createdBy: CreatedBy!
  """The credit note number, unique within the organization."""
  creditNoteNumber: String!
  "ISO 4217 currency code."
  currency: String!
  """The date after which the credit can no longer be applied."""
  expiryDate: DateTime
  "The unique ID of this record."
  id: ID!
  """Notes for staff only."""
  internalNotes: String
  """The date the note was issued."""
  issueDate: DateTime!
  """The lines of the note."""
  items: [CreditNoteItem!]!
  """
  True when the lines follow what a return's inspection accepted and cannot be edited.
  """
  linesLocked: Boolean!
  """Notes shown on the note."""
  notes: String
  """The document the note was raised against."""
  originalDocument: OriginalDocument
  """The ID of the invoice the note is raised against."""
  originalInvoiceId: ID
  "The ID of the partner."
  partnerId: String!
  """The name of the customer or vendor."""
  partnerName: String!
  """Whether the partner is a customer or a vendor."""
  partnerType: String!
  """Why the note was raised."""
  reason: String!
  """How much of the note is still available to apply."""
  remainingAmount: Float!
  """
  Where the note stands: DRAFT, PENDING, APPROVED, PARTIALLY_APPLIED, FULLY_APPLIED or CANCELLED.
  """
  status: String!
  """The note total including tax, in the note's currency."""
  totalAmount: Float!
  """
  What the note is for: SALES_RETURN, PURCHASE_RETURN, PRICE_ADJUSTMENT, GOODWILL or OTHER.
  """
  type: String!
}

"""The credit note to raise when a return is processed."""
input CreditNoteDetailsInput {
  """A signed adjustment to the total."""
  adjustments: Float
  """The note amount before tax."""
  amount: Float!
  """Notes shown on the note."""
  notes: String
  """The tax on the note."""
  taxAmount: Float!
}

"""Filters and sorting for the credit note list."""
input CreditNoteFiltersInput {
  """Only notes issued on or before this date."""
  endDate: DateTime
  """
  Leave out notes of these types. The credit note list leaves out PURCHASE_RETURN, which belongs to debit notes.
  """
  excludeTypes: [String!]
  "The ID of the partner."
  partnerId: String
  """Only notes for this kind of partner, customer or vendor."""
  partnerType: String
  "Text to search for."
  search: String
  """The column to sort by. Defaults to the credit note number."""
  sortBy: CreditNoteSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only notes issued on or after this date."""
  startDate: DateTime
  """Only notes in one of these statuses."""
  status: [String!]
  """Only notes of this type."""
  type: String
}

"""One line of a credit note."""
type CreditNoteItem {
  """The line amount."""
  amount: Float!
  """What the credit is for on this line."""
  description: String!
  """The discount on the line, rounded to the currency."""
  discountAmount: Float
  """The discount on the line, in percent."""
  discountPercent: Float
  "The unique ID of this record."
  id: ID!
  "The ID of the product."
  productId: String
  """The quantity credited."""
  quantity: Float!
  """The tax on the line."""
  taxAmount: Float
  """The tax split as a list of tax type, rate and tax amount."""
  taxBreakdown: JSON
  """The tax rate on the line, in percent."""
  taxRate: Float
  """
  The line total including tax. Prefer this over amount, which means something different on a manual note and a return-based note.
  """
  totalAmount: Float
  """The price of one unit."""
  unitPrice: Float!
  "The ID of the product variant."
  variantId: String
}

"""A column the credit note list can be sorted by."""
enum CreditNoteSortField {
  """When the credit note was created."""
  CREATED_AT
  """The issue date."""
  ISSUE_DATE
  """The total amount."""
  TOTAL_AMOUNT
}

"""Totals for the credit note list."""
type CreditNoteSummary {
  """How many are applied."""
  appliedNotes: Float!
  """The part of that value already applied."""
  appliedValue: Float!
  """The same figures split by credit note type."""
  byType: [CreditNoteTypeBreakdown!]!
  """How many are drafts."""
  draftNotes: Float!
  """How many have expired."""
  expiredNotes: Float!
  """How many are issued."""
  issuedNotes: Float!
  """The part of that value still available to apply."""
  remainingValue: Float!
  """How many credit notes match."""
  totalNotes: Float!
  """The total value of the notes."""
  totalValue: Float!
}

"""Credit notes of one type, counted and totalled."""
type CreditNoteTypeBreakdown {
  """How many notes have this type."""
  count: Float!
  """The credit note type."""
  type: String!
  """The total value of those notes."""
  value: Float!
}

"""How much of one customer's credit limit is in use."""
type CreditUtilization {
  """The credit limit."""
  creditLimit: Float!
  "The ID of the customer."
  customerId: String!
  """The name of the customer."""
  customerName: String!
  """The share of the limit in use, in percent."""
  percentage: Float!
  """The credit in use."""
  utilized: Float!
}

"""A currency the organization can use."""
type Currency {
  """The currency code, such as an ISO 4217 code."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  """How many decimal places amounts show."""
  decimalPlaces: Int!
  """The character between the whole and decimal parts."""
  decimalSeparator: String
  """An example of how an amount is shown."""
  format: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """True when this is the organization's base currency."""
  isBaseCurrency: Boolean!
  """The name of the currency."""
  name: String!
  """The position in lists, lowest first."""
  sortOrder: Int
  """The currency symbol."""
  symbol: String!
  """Where the symbol goes: before or after the amount."""
  symbolPosition: String
  """The character between thousands."""
  thousandSeparator: String
  """The kind of currency: fiat, crypto or commodity."""
  type: CurrencyType!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A currency to pick from."""
type CurrencyListItem {
  """The currency code."""
  code: String!
  """How many decimal places amounts use."""
  decimalPlaces: Int!
  """The name of the currency."""
  name: String!
  """The currency symbol."""
  symbol: String!
}

"""Type of currency (FIAT, CRYPTO, COMMODITY)"""
enum CurrencyType {
  """A commodity-backed currency."""
  COMMODITY
  """A cryptocurrency."""
  CRYPTO
  """A government-issued currency."""
  FIAT
}

"""A customer: a partner with the customer role."""
type Customer {
  """The customer's addresses."""
  addresses: [Address!]
  """The sales rep who owns the customer."""
  assignedSalesRep: CreatedByUser
  """The ID of the sales rep who owns the customer."""
  assignedSalesRepId: String
  """The customer code."""
  code: String!
  """The customer's contacts."""
  contacts: [Contact!]
  "When the record was created."
  createdAt: DateTime!
  """The user who created the customer."""
  createdByUser: CreatedByUser
  """The credit limit. 0 or less means unlimited."""
  creditLimit: Float!
  """The customer's current balance."""
  currentBalance: Float!
  """The customer-side account details."""
  customerAccount: CustomerAccount
  """
  The customer's tier label, set automatically or by hand, for example GOLD or SILVER.
  """
  customerTier: String
  """The name of the customer's tier."""
  customerTierName: String
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the customer is."""
  description: String
  """The name to show for the customer."""
  displayName: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """The customer's industry."""
  industry: String
  """The legal name of the customer."""
  legalName: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The name of the customer."""
  name: String!
  """Notes about the customer."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """
  What the customer still owes: the total outstanding on open sales invoices, in the organization's base currency.
  """
  outstandingReceivable: Float
  """The payment terms agreed with the customer."""
  paymentTerms: String!
  """The rep the customer was moved away from."""
  previousSalesRep: CreatedByUser
  """The ID of the rep the customer was moved away from."""
  previousSalesRepId: String
  """When the previous rep acknowledged the move."""
  reassignmentAcknowledgedAt: DateTime
  """The customer's company registration number."""
  registrationNumber: String
  """When the customer was moved to the current rep."""
  repReassignedAt: DateTime
  """The roles of the partner, such as customer or vendor."""
  roles: [PartnerRole!]!
  """The status of the customer."""
  status: PartnerStatus!
  """Tags on the customer."""
  tags: [String!]
  """The customer's tax ID."""
  taxId: String
  """The kind of customer."""
  type: String
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The vendor-side account details, when the partner is also a vendor."""
  vendorAccount: VendorAccount
  """The customer's website."""
  website: String
}

"""
The customer side of a partner: credit, tax exemption and buying details.
"""
type CustomerAccount {
  """The credit still available."""
  availableCredit: Float!
  """The average order value. Deprecated: read lifetimeFacts instead."""
  averageOrderValue: Float!
  """How the customer buys."""
  buyingProcess: String
  """How the customer prefers to be contacted."""
  communicationPreference: String!
  """The size of the customer's company."""
  companySize: String
  "When the record was created."
  createdAt: DateTime!
  """The credit limit. 0 or less means unlimited."""
  creditLimit: Float!
  """The customer's credit rating."""
  creditRating: String
  """The customer's current balance."""
  currentBalance: Float!
  """The customer code."""
  customerCode: String!
  """The customer's business type."""
  customerType: String
  """Who makes the buying decision."""
  decisionMaker: String
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """The date of the last order. Deprecated: read lifetimeFacts instead."""
  lastOrderDate: DateTime
  """The date of the last payment. Deprecated: read lifetimeFacts instead."""
  lastPaymentDate: DateTime
  """The customer's loyalty points."""
  loyaltyPoints: Int!
  """The customer's loyalty tier."""
  loyaltyTier: String
  """True when the customer agreed to marketing messages."""
  marketingOptIn: Boolean!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """How many days the customer is overdue."""
  overdueDays: Int!
  "The ID of the partner."
  partnerId: String!
  """The currency of the customer's documents."""
  preferredCurrency: String!
  """The customer's preferred shipping method."""
  preferredShippingMethod: String
  """When the customer's buying peaks."""
  seasonality: String
  """Special instructions for handling the customer."""
  specialInstructions: String
  """True when the customer is exempt from tax."""
  taxExempt: Boolean
  """The number of the exemption certificate."""
  taxExemptCertificateNumber: String
  """Why the customer is exempt from tax."""
  taxExemptReason: String
  """The first day the exemption is valid."""
  taxExemptValidFrom: DateTime
  """The last day the exemption is valid."""
  taxExemptValidTo: DateTime
  """
  The total value of the customer's orders. Deprecated: read lifetimeFacts instead.
  """
  totalOrderValue: Float!
  """
  How many orders the customer placed. Deprecated: read lifetimeFacts instead.
  """
  totalOrders: Int!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""The customer's account figures."""
type CustomerAccountInfo {
  """
  creditLimit − Σ open SALES-invoice outstanding, never negative. NULL when the customer's credit is unlimited (creditLimit <= 0, see creditUnlimited) — never 0, which would read as 'no credit left'. 0 by convention when creditLimitEnabled is false.
  """
  availableCredit: Float
  """The name of the customer's company."""
  companyName: String!
  """The credit limit."""
  creditLimit: Float!
  """
  Whether this org enforces credit limits (Organization.creditLimitEnabled, default true). When false, creditLimit and availableCredit are 0 BY CONVENTION and must not be read as 'no credit left' — the credit module is simply off. Clients gate credit UI on this, never on a zero amount.
  """
  creditLimitEnabled: Boolean!
  """
  True when the org enforces credit limits AND this customer has no limit (creditLimit <= 0 = unlimited, the confirm gate's own rule). availableCredit is then null: render 'Unlimited' and never cap On account.
  """
  creditUnlimited: Boolean!
  """The current balance."""
  currentBalance: Float!
  """
  False when this buyer cannot order On account: their payment term was retired by the tenant, or (with no term of their own) the tenant default is not a credit term. Clients hide On account on this flag; checkout refuses it with ON_ACCOUNT_UNAVAILABLE either way.
  """
  onAccountAvailable: Boolean!
  """How many days the account is overdue."""
  overdueDays: Int!
  """The customer code."""
  partnerCode: String
  "The ID of the partner."
  partnerId: ID!
  """The payment terms agreed with the customer."""
  paymentTerms: String
  """How many orders the customer placed."""
  totalOrders: Int!
}

"""
One line inside a batch add. Same shape as CustomerAddBuyingListItemInput minus listId, which the batch carries once.
"""
input CustomerAddBuyingListItemEntry {
  "The ID of the product."
  productId: ID!
  """The quantity to add."""
  quantity: Float!
  """Defaults to the variant's selling/base UOM (mirrors cart)."""
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
}

"""Adds an item to a buying list."""
input CustomerAddBuyingListItemInput {
  """The ID of the buying list."""
  listId: ID!
  "The ID of the product."
  productId: ID!
  """
  The quantity to add. It is added to any existing line for the same variant and unit of measure. Must be greater than zero.
  """
  quantity: Float!
  """Defaults to the variant's selling/base UOM (mirrors cart)."""
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
}

"""An address of the customer."""
type CustomerAddress {
  """The city."""
  city: String!
  """The phone number for this location, not the account's."""
  contactPhone: String
  """The country."""
  country: String
  "The unique ID of this record."
  id: ID!
  "Whether this is the default."
  isDefault: Boolean!
  """
  True when the address also serves the other role: a shipping address that can be billed to, or a billing address that can be delivered to.
  """
  isDualPurpose: Boolean!
  """A label for the address."""
  label: String
  """The latitude of the address on the map."""
  latitude: Float
  """The longitude of the address on the map."""
  longitude: Float
  """The postal code."""
  postalCode: String!
  """The state or region."""
  state: String!
  """The first line of the street address."""
  street1: String!
  """The second line of the street address."""
  street2: String
  """The kind of address, for example shipping or billing."""
  type: AddressType!
}

"""An address of the customer."""
input CustomerAddressInput {
  """The city."""
  city: String!
  """The phone number at the address."""
  contactPhone: String
  """The country."""
  country: String!
  """create this address as a sales branch (requires label)."""
  isBranch: Boolean
  """
  This address serves both shipping and billing (read together with `type`).
  """
  isDualPurpose: Boolean
  """A label for the address."""
  label: String
  """The latitude of the address on the map."""
  latitude: Float
  """The longitude of the address on the map."""
  longitude: Float
  """
  branch order-value ceiling (org base currency; null = unlimited; > 0 only).
  """
  orderLimit: Float
  """The postal code."""
  postalCode: String!
  """The state or region."""
  state: String
  """The first line of the street address."""
  street1: String!
  """The second line of the street address."""
  street2: String
  """
  SHIPPING to deliver here, BILLING to invoice here. A new address defaults to SHIPPING.
  """
  type: CustomerAddressType
}

"""
Address classification a buyer may set from the portal: SHIPPING (deliver here) or BILLING (invoice here).
"""
enum CustomerAddressType {
  """A billing address."""
  BILLING
  """A shipping address."""
  SHIPPING
}

"""
One age band of the customer's open receivable, as of the end of the period. The bands follow the organization's aging policy.
"""
type CustomerAgingBucket {
  """The label of the band, such as current, 1-30 or 90+. Show it as it is."""
  bucket: String!
  """How many open invoices are in the band."""
  count: Int!
  """The amount still owed in the band."""
  value: Float!
}

"""Customer figures for the period."""
type CustomerAnalytics {
  """How many were active."""
  activeCustomers: Int!
  """The average number of orders per customer."""
  averageOrdersPerCustomer: Float!
  """The share of customers who stopped buying, in percent."""
  churnRate: Float!
  """Customer numbers over time."""
  customerGrowth: [CustomerGrowth!]!
  """The average revenue a customer brings over their lifetime."""
  customerLifetimeValue: Float!
  """Customers split by tier."""
  customersByTier: [CustomerTierAnalytics!]!
  """How many joined."""
  newCustomers: Int!
  """The customers who bring in the most revenue."""
  topCustomersByRevenue: [TopCustomerRevenue!]!
  """How many customers there are."""
  totalCustomers: Int!
}

"""A group of customers worked out for the reports."""
type CustomerAnalyticsSegment {
  """The average order value in the segment."""
  averageOrderValue: Float!
  """How many customers are in it."""
  count: Int!
  """Its share of all customers, in percent."""
  percentage: Float!
  """The name of the segment."""
  segment: String!
  """The revenue from the segment."""
  totalRevenue: Float!
}

"""
Result of an approve/decline decision. orderId/orderNumber set on approve.
"""
type CustomerApprovalDecisionResult {
  """
  The ID of the order the approval produced. Null when approving did not create an order.
  """
  orderId: ID
  """The number of that order."""
  orderNumber: String
  """The approval request after the decision."""
  request: CustomerOrderApprovalView!
}

"""One line of a parked approval request (snapshot of the repriced cart)."""
type CustomerApprovalLine {
  """
  Pre-discount per-unit price, so the detail screen can show list vs paid.
  """
  baseUnitPrice: Float
  """
  Line discount frozen at request time. Absent (not 0) on requests parked before discounts were snapshotted.
  """
  discountAmount: Float
  """
  TRUE when the discount and pre-discount unit price were DERIVED from the variant's price today, not read from the snapshot — the request predates discount capture. The UI must label such a figure as an estimate; it is not what the buyer was quoted.
  """
  discountDerived: Boolean
  """
  Variant image, else the product's — buyer-surface precedence (variant-then-product).
  """
  imageUrl: String
  """The line total."""
  lineTotal: Float!
  "The ID of the product."
  productId: ID
  """The name of the product."""
  productName: String!
  """The quantity."""
  quantity: Float!
  """The SKU of the variant."""
  sku: String
  """The tax on the line."""
  taxAmount: Float
  """The tax rate on the line, in percent."""
  taxRate: Float
  """The price of one unit."""
  unitPrice: Float!
  """The unit of measure."""
  uomCode: String
  """
  The unit's full name ("Each", "Case of 12") resolved from the snapshot's uomId — the snapshot itself keeps only the short code, which is not what a buyer reads.
  """
  uomName: String
  """
  The variant this line was for — carried so a client can open the product, and so the server can resolve the variant's current name/image.
  """
  variantId: ID
  """
  The variant's own name (resolved from the snapshot's variantId at read time).
  """
  variantName: String
}

"""
the approval request minted when an over-limit checkout parks instead of creating an order.
"""
type CustomerApprovalRequestSummary {
  "ISO 4217 currency code."
  currency: String!
  "The unique ID of this record."
  id: ID!
  """REQ-… (per-org sequence, minted server-side)."""
  requestNumber: String!
  """Pending | Approved | Declined (DESIGN-SPEC approvals vocabulary)."""
  status: String!
  """The total of the order waiting for approval."""
  totalAmount: Float!
}

"""
approver scope — COMPANY (all branches + branchless requests; no PartnerBranchApprover rows) or BRANCH (only the granted branch addresses).
"""
enum CustomerApproverScope {
  """Approvers cover the orders of their own branch."""
  BRANCH
  """Approvers cover the orders of the whole company."""
  COMPANY
}

"""the effective approver scope after setCustomerApproverScope."""
type CustomerApproverScopeResult {
  """Granted branch address ids ([] under COMPANY)."""
  branchAddressIds: [ID!]!
  """The approver scope now in force."""
  scope: CustomerApproverScope!
  "The ID of the user."
  userId: ID!
}

"""
The seller's picture for one value of a variant attribute, such as the Orange swatch of Colour.
"""
type CustomerAttributePicture {
  """
  The attribute in its canonical spelling: lower case, with spelling variants folded (Colour and Color are one).
  """
  attributeKey: String!
  """The picture's URL."""
  imageUrl: String!
  """The attribute value, exactly as variants carry it."""
  value: String!
}

"""The result of a customer sign in."""
type CustomerAuthResponse {
  """The token to send with requests."""
  accessToken: String!
  """How many seconds the access token lasts."""
  expiresIn: Int!
  """The token to get a new access token."""
  refreshToken: String!
  """The token that identifies the session."""
  sessionToken: String
  """The kind of token, for example Bearer."""
  tokenType: String!
  """The signed-in customer user."""
  user: CustomerUser!
}

"""
Seller bank details for EFT (from PortalConfiguration.displayBankAccountId; — never hardcoded).
"""
type CustomerBankDetails {
  """The name on the account."""
  accountName: String!
  """The account number."""
  accountNumber: String!
  """The name of the bank."""
  bankName: String!
  """The bank branch or sort code."""
  branchCode: String
  "ISO 4217 currency code."
  currencyCode: String!
  """The IBAN."""
  iban: String
  """
  "<customerCode> / <orderNumber>" when orderId given (e.g. "AC-2214 / SO-1042").
  """
  paymentReference: String
  """The SWIFT or BIC code."""
  swiftCode: String
}

"""
a partner sales branch — an Address with isBranch = true. The label is the branch name; pendingApprovalCount feeds the deactivation warning (EDGE #4).
"""
type CustomerBranch {
  """How many approvers the branch has."""
  approverCount: Int!
  """The approvers of the branch."""
  approvers: [CustomerBranchMemberSummary!]!
  "The unique ID of this record."
  id: ID!
  """Branch active = Address.isActive."""
  isActive: Boolean!
  """True when this is a branch of the company."""
  isBranch: Boolean!
  """The branch display name (the address label)."""
  label: String
  """How many members the branch has."""
  memberCount: Int!
  """The members of the branch."""
  members: [CustomerBranchMemberSummary!]!
  """
  Order-value ceiling for any manager ordering for this branch (org base currency; null = unlimited).
  """
  orderLimit: Float
  """
  PENDING approval requests parked against this branch (deactivation warning — EDGE #4).
  """
  pendingApprovalCount: Int!
}

"""brief user card on a branch (manager or approver grant)."""
type CustomerBranchMemberSummary {
  "Email address."
  email: String!
  """The member's first name."""
  firstName: String!
  """The member's last name."""
  lastName: String!
  """CUSTOMER_ADMIN | CUSTOMER_BUYER | CUSTOMER_VIEWER."""
  role: String!
  "The ID of the user."
  userId: ID!
}

"""A brand a customer can shop."""
type CustomerBrand {
  """The brand code."""
  code: String!
  """What the brand is."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The URL of the brand logo."""
  logoUrl: String
  """The name of the brand."""
  name: String!
  """How many products the brand has."""
  productCount: Int!
}

"""A buying-list line; prices computed at read time (never stored)."""
type CustomerBuyingListItemView {
  """
  Display name of the colleague who added this line. The list is shared, so a buyer needs to know whose line they are about to change.
  """
  addedByName: String
  "The unique ID of this record."
  id: ID!
  """
  Primary image, variant-first then product — the precedence every buyer surface uses (the console inverts it). Null when neither carries one; the app draws its own placeholder.
  """
  imageUrl: String
  """The line total."""
  lineTotal: Float!
  """Ceiling for this line's pack, same units. Null = unbounded."""
  maxOrderQuantity: Float
  """
  Smallest orderable quantity for this line's pack. The pack's own minOrderQty wins over the variant's base-unit one; 1 when neither is set.
  """
  minOrderQuantity: Float!
  """Quantity must be a multiple of this. 1 means any whole step."""
  orderMultiple: Float!
  """
  Pre-discount unit price, for a strike-through reference — same field name and meaning as MobileOrderItem.originalUnitPrice. Undefined when there is nothing to strike through (no discount applied, or pricing failed and unitPrice fell back to 0).
  """
  originalUnitPrice: Float
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The quantity on the list."""
  quantity: Float!
  """The SKU of the variant."""
  sku: String
  """
  This line's pack, buyer-facing (e.g. "Case", "Each") — the SAME UnitOfMeasure.name/code fallback every order surface uses. Null only when the pack's UOM row itself has neither.
  """
  unitLabel: String
  """Computed at read via the display contract."""
  unitPrice: Float!
  "The ID of the unit of measure."
  uomId: ID!
  "The ID of the product variant."
  variantId: ID!
  """The name of the variant."""
  variantName: String
}

"""A durable partner-shared buying list. screen 12."""
type CustomerBuyingListView {
  """
  Whether THIS buyer may delete the whole list. Separate from canEdit because that rule is expected to tighten (creator-only).
  """
  canDelete: Boolean!
  """
  Whether THIS buyer may add or edit lines. Server-computed from the role allowlist so the client never re-implements the policy.
  """
  canEdit: Boolean!
  """Display name of whoever created this partner-shared list."""
  createdByName: String
  "ISO 4217 currency code."
  currency: String!
  """Σ lineTotal, computed at read time."""
  estimatedTotal: Float!
  "The unique ID of this record."
  id: ID!
  """
  items.length — lets a list CARD render without the caller selecting every line.
  """
  itemCount: Int!
  """The items on the list."""
  items: [CustomerBuyingListItemView!]!
  """When the list was last used."""
  lastUsedAt: DateTime
  """The name of the list."""
  name: String!
  """A note on the list."""
  note: String
}

"""
One list's slice of a batch write: the lines to add to it and/or the lines to remove from it.
"""
input CustomerBuyingListWriteGroup {
  """The items to add."""
  add: [CustomerAddBuyingListItemEntry!]
  """The ID of the buying list."""
  listId: ID!
  """The IDs of the items to remove."""
  removeItemIds: [ID!]
}

"""
The outcome of ONE line in a batch write. Per-item rather than all-or-nothing: one unorderable line must not discard the others the buyer got right.
"""
type CustomerBuyingListWriteResult {
  """
  Machine-readable failure code (VARIANT_NOT_FOUND, LIST_ITEM_NOT_FOUND, QUANTITY_MUST_BE_POSITIVE,...) — the same strings the single-item mutations throw.
  """
  error: String
  """Position within this group's add/removeItemIds array."""
  index: Int!
  """The list this result belongs to."""
  listId: ID!
  """True when it was done."""
  ok: Boolean!
  """Which half of the write this result is."""
  op: BuyingListWriteOp!
  """variantId on an add, itemId on a remove — what this row was."""
  ref: ID!
}

"""
A batch write's outcome: every touched list in full (one authoritative cache write each) plus one result per submitted line.
"""
type CustomerBuyingListsWriteView {
  """The buying lists after the write."""
  lists: [CustomerBuyingListView!]!
  """The outcome of each part of the write."""
  results: [CustomerBuyingListWriteResult!]!
}

"""
How regularly the customer orders and whether they are late by their own standard. It looks at the whole order history up to the end of the period.
"""
type CustomerCadence {
  """
  Whole days from the last committed order to the end of the period. It is set even when there is too little history to read a rhythm.
  """
  daysSinceLastOrder: Int
  """
  True when a rhythm can be read: at least 3 orders and a median gap of at least a day. Otherwise the rhythm figures are empty.
  """
  enough: Boolean!
  """
  The last order plus the median gap. It may be in the past, which is the finding.
  """
  expectedNextOrderAt: DateTime
  """
  The gaps between orders that closed inside the period. Empty unless enough is true.
  """
  gaps: [CustomerGapPoint!]!
  """
  How many committed orders there are up to the end of the period, over the whole relationship.
  """
  historyOrderCount: Int!
  """The longest gap between orders, in days."""
  longestGapDays: Float
  """The median days between orders. Empty unless enough is true."""
  medianGapDays: Float
}

"""
The search result for customers and buyers: the storefront catalog and nothing else.
"""
type CustomerCatalogSearchResult {
  """The matching brands."""
  brands: [GlobalSearchBrandFullResult!]!
  """The matching categories."""
  categories: [GlobalSearchCategoryFullResult!]!
  """The matching products."""
  products: [GlobalSearchProductResult!]!
}

"""A category a customer can shop."""
type CustomerCategory {
  """The child categories."""
  children: [CustomerCategory!]
  """The category code."""
  code: String!
  """What the category holds."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The URL of the category image."""
  imageUrl: String
  """The depth in the tree, starting at 1 for a root."""
  level: Int!
  """The name of the category."""
  name: String!
  """The ID of the parent category."""
  parentId: String
  """
  Count of matching ProductVariant rows in this category's subtree (the PLP lists at variant grain) — not a distinct-Product count.
  """
  productCount: Int!
}

"""A page of categories."""
type CustomerCategoryConnection {
  """True when there are more after this page."""
  hasNextPage: Boolean!
  """The categories on this page."""
  items: [CustomerCategory!]!
  """The cursor to pass to get the next page."""
  nextCursor: String
  """How many categories there are in all."""
  totalCount: Int!
}

"""
Invoiced value in one top-level category, found by walking up from the product's main category.
"""
type CustomerCategoryRow {
  "The ID of the category."
  categoryId: ID
  """
  Its share in the comparison period. Empty when that period had nothing invoiced.
  """
  comparisonSharePct: Float
  """The name of the category."""
  name: String!
  """Its share of the invoiced value, in percent."""
  sharePct: Float!
  """The invoiced value."""
  value: Float!
}

"""What one customer has paid in settled collections."""
type CustomerCollection {
  """
  The total collected from the customer, in the organization's base currency.
  """
  amount: Float!
  """How many settled collections the customer made."""
  count: Int!
  """The ID of the customer."""
  customerId: String!
  """The name of the customer."""
  customerName: String!
}

"""A commission rate set for one customer."""
type CustomerCommissionRate {
  """The name of the customer."""
  customerName: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "The ID of the partner."
  partnerId: String!
  """The rate, in percent."""
  rate: Float!
}

"""A new buying list."""
input CustomerCreateBuyingListInput {
  """The name of the list."""
  name: String!
  """A note on the list."""
  note: String
}

"""Asks to return goods from an order."""
input CustomerCreateReturnInput {
  """The lines to return."""
  items: [CustomerReturnLineInput!]!
  """Notes about the return."""
  notes: String
  """The ID of the order."""
  orderId: ID!
  """
  DAMAGED_IN_TRANSIT | WRONG_ITEM | SHORT_DELIVERY | QUALITY_ISSUE | OTHER.
  """
  reason: String!
}

"""
The customer's credit position, with the same figures as the credit card on the partner overview.
"""
type CustomerCredit {
  """Cash paid but not yet allocated, sitting on the account."""
  advances: Float!
  """The base currency of the money values."""
  baseCurrency: String!
  """Advances plus note credits."""
  creditOnAccount: Float!
  """The credit currently in use."""
  currentExposure: Float!
  """
  True when the organization enforces credit limits. When false, the limit and headroom mean nothing and are hidden.
  """
  enabled: Boolean!
  """The limit minus the current exposure. Empty when unlimited."""
  headroom: Float
  """The total outstanding on open invoices, as the credit check counts it."""
  invoiceExposure: Float!
  """
  The credit limit in the base currency. 0 means unlimited or unset. Read unlimited instead of testing for 0.
  """
  limit: Float!
  """The remaining balance of credit notes issued to the customer."""
  noteCredits: Float!
  """The value of committed credit-terms orders not yet invoiced."""
  uninvoicedCommitment: Float!
  """True when there is no limit."""
  unlimited: Boolean!
}

"""The customer's dashboard figures."""
type CustomerDashboard {
  """How many orders are active."""
  activeOrders: Int!
  """
  The credit still available. Empty means unlimited, unless balanceUnavailable is true, when it means unknown.
  """
  availableCredit: Float
  """
  True when the account figures could not be loaded. The rest of the dashboard still loads.
  """
  balanceUnavailable: Boolean!
  """
  What is owed on open invoices. Empty when the account could not be read, which is never shown as 0.
  """
  outstandingBalance: Float
  """How many invoices are overdue."""
  overdueInvoices: Int!
  """How many quotes are pending."""
  pendingQuotes: Int!
  """The most recent orders."""
  recentOrders: [CustomerOrder!]!
  """The signed-in person's email address."""
  viewerEmail: String
  """The signed-in person's first name, for the greeting."""
  viewerFirstName: String
}

"""The customer surfaces the shaping applies to."""
type CustomerDeliveryApplyTo {
  """True when the shaping applies to the buyer app."""
  buyerApp: Boolean!
  """True when the shaping applies to the customer portal."""
  portal: Boolean!
}

"""The customer surfaces the shaping applies to."""
input CustomerDeliveryApplyToInput {
  """True to apply it to the buyer app."""
  buyerApp: Boolean!
  """True to apply it to the customer portal."""
  portal: Boolean!
}

"""Which delivery details customer screens show."""
type CustomerDeliveryDetails {
  """Show the courier's logo."""
  courierLogo: Boolean!
  """
  Always true while tracking is FULL (the tracking link names the carrier).
  """
  courierName: Boolean!
  """Show the estimated delivery date."""
  estimate: Boolean!
  """Show the name of the service."""
  serviceName: Boolean!
}

"""Which delivery details customer screens show."""
input CustomerDeliveryDetailsInput {
  """Show the courier's logo."""
  courierLogo: Boolean!
  """Show the courier's name."""
  courierName: Boolean!
  """Show the estimated delivery date."""
  estimate: Boolean!
  """Show the name of the service."""
  serviceName: Boolean!
}

"""
The live delivery option the buyer chose at checkout (live-priced stores only). `fee` is what the buyer was charged for delivery, in `currency`; it is already included in the order's delivery amount. `label` is the row title; courier and service are null when the store does not show them to customers.
"""
type CustomerDeliverySelection {
  """The courier, or null when the store hides it from customers."""
  carrierName: String
  "ISO 4217 currency code."
  currency: String!
  """The delivery fee the customer agreed to."""
  fee: Float!
  """
  What to show as the delivery choice: the speed name, else "courier · service" from what is shown, else "Delivery" (translate that one on the client).
  """
  label: String!
  """When the fee was quoted."""
  quotedAt: DateTime
  """The courier's service, or null when hidden (or not recorded)."""
  serviceLevelName: String
  """
  The delivery speed the buyer picked (e.g. the store's "Priority"), or null when they picked a service or the store picked for them.
  """
  speedName: String
}

"""The customer's current non-tier discount scheme, if one applies."""
type CustomerDiscountSnapshot {
  """The code of the scheme."""
  code: String
  """
  Whole days from the end of the period until the scheme ends. Empty for an open-ended scheme.
  """
  daysUntilExpiry: Int
  """The fixed discount amount."""
  fixedAmountValue: Float
  "The unique ID of this record."
  id: String!
  """The name of the scheme."""
  name: String!
  """The discount in percent."""
  percentageValue: Float
  """PERCENTAGE or FIXED_AMOUNT."""
  type: String!
  """When the scheme ends."""
  validTo: DateTime
}

"""
A buyer-registered EFT payment: created PENDING (never auto-allocated); the seller verifies. Errors: EFT_AMOUNT_EXCEEDS_OUTSTANDING.
"""
type CustomerEftPaymentResult {
  """The amount registered."""
  amount: Float!
  "ISO 4217 currency code."
  currency: String!
  "The ID of the payment."
  paymentId: ID!
  """The number of the registered payment."""
  paymentNumber: String!
  """PENDING until the seller verifies the transfer."""
  status: String!
}

"""How engaged one customer is."""
type CustomerEngagement {
  """How many emails the customer opened."""
  emailOpens: Int!
  """When the customer last ordered."""
  lastOrderAt: DateTime
  """The name of the customer."""
  name: String!
  """How many orders the customer placed in the period."""
  orders: Int!
  "The ID of the partner."
  partnerId: String!
}

"""How customers engage with the organization."""
type CustomerEngagementAnalytics {
  """How many customers were active in the period."""
  activeCustomers: Int!
  """Customers who may be slipping away."""
  atRisk: [CustomerEngagement!]!
  """The share of sent emails that were opened, in percent."""
  emailOpenRatePct: Float!
  """Logins over the period."""
  loginTrend: [TrendPoint2!]!
  """How many customers joined in the period."""
  newCustomers: Int!
  """The most engaged customers."""
  topEngaged: [CustomerEngagement!]!
}

"""
How the customer's account is engaging with the buyer app and portal, across every user on the account.
"""
type CustomerEngagementFacts {
  """The value of those orders, in the base currency."""
  abandonedPaymentValue30d: Float!
  """
  How many online checkouts closed unpaid in 30 days, cancelled or expired.
  """
  abandonedPayments30d: Int!
  """How many different customer users had a session in those 30 days."""
  activeUsers30d: Int!
  """Add-to-cart actions in 30 days."""
  appCartAdds30d: Int!
  """Remove-from-cart actions in 30 days."""
  appCartRemoves30d: Int!
  """Product detail views in 30 days, in the app and portal."""
  appProductViews30d: Int!
  """Catalogue searches in 30 days. The search term is never stored."""
  appSearches30d: Int!
  """Of those, searches that returned no product."""
  appZeroResultSearches30d: Int!
  """
  How many checkouts the server refused in the 7 days to the end of the period.
  """
  checkoutBlocked7d: Int!
  """
  The same count for the 30 days before. It is a lower bound, since old session rows can be deleted.
  """
  comparisonActiveUsers30d: Int!
  """
  The share of outbound emails opened, from the same figure as the quotes section.
  """
  emailOpenRatePct: Float
  """When the app was last used."""
  lastAppActivityAt: DateTime
  """The most recent app platform: android, ios or web."""
  lastAppPlatform: String
  """The most recent app version."""
  lastAppVersion: String
  """The reason for the latest refusal."""
  lastCheckoutBlockReason: String
  """When the customer last replied to a quote in the period."""
  lastCustomerReplyAt: DateTime
  """
  The most recent session over the whole history up to the end of the period.
  """
  lastLoginAt: DateTime
  """
  How many sessions the customer's users started in the 30 days to the end of the period.
  """
  logins30d: Int!
  """The most viewed products, at most five, most views first."""
  mostViewedProducts: [CustomerViewedProduct!]!
  """
  Whole hours since the busiest cart last changed, measured from the end of the period.
  """
  openCartIdleHours: Int
  """How many items the active carts hold."""
  openCartItemCount: Int!
  """When the carts last changed."""
  openCartUpdatedAt: DateTime
  """
  The value of every active cart on the account. Empty when there is no active cart.
  """
  openCartValue: Float
  """How many customer users are set up on the account, active or not."""
  portalUserCount: Int!
}

"""One fact behind a finding."""
type CustomerEvidence {
  """The amount in the base currency. Empty when the figure is in value."""
  amount: Float
  """What the fact is."""
  label: String!
  """The figure as text. Empty when it is money."""
  value: String
}

"""Whether a customer account exists."""
type CustomerExistsResponse {
  """
  True when a CUSTOMER user with this email already exists in this tenant.
  """
  exists: Boolean!
  """
  PortalConfiguration.allowSelfRegistration (default true). When exists=false: true → route to registration; false → show a 'registration disabled' message.
  """
  selfRegistrationEnabled: Boolean!
}

"""A partner-wide frequently-bought item (Quick order, screen 6)."""
type CustomerFrequentItem {
  "ISO 4217 currency code."
  currency: String!
  """The URL of the product image."""
  imageUrl: String
  """When the customer last bought it."""
  lastBoughtAt: DateTime!
  """The largest quantity for one line in this unit. Empty means no cap."""
  maxOrderQuantity: Float
  """
  The smallest quantity for one line in this unit. The stricter of the variant's minimum and the pack's own wins, as when an order is created.
  """
  minOrderQuantity: Float!
  """
  Quantities step by this, counted from 0. 1 or less means no whole-number step.
  """
  orderMultiple: Float!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The SKU of the variant."""
  sku: String
  """How many times the customer ordered it."""
  timesOrdered: Int!
  """Current effective price, resolved server-side."""
  unitPrice: Float!
  """The unit of measure."""
  uomCode: String
  "The ID of the unit of measure."
  uomId: ID!
  "The ID of the product variant."
  variantId: ID!
  """The name of the variant."""
  variantName: String
}

"""One stage of the customer's quote funnel."""
type CustomerFunnelStage {
  """How many quotes are in the stage."""
  count: Int!
  """The stage."""
  key: String!
  """
  Their value. The funnel need not shrink, since a quote can convert without being viewed.
  """
  value: Float!
}

"""One closed gap between two consecutive committed orders."""
type CustomerGapPoint {
  """The days from the previous committed order."""
  days: Float!
  """The date of the later order, which closed the gap."""
  orderDate: DateTime!
}

"""Customer numbers for one period."""
type CustomerGrowth {
  """How many customers joined."""
  newCustomers: Int!
  """The period."""
  period: String!
  """How many customers there were in all."""
  totalCustomers: Int!
}

"""
A health score made of recency, frequency, monetary and payment parts, each out of 25. It is empty unless all four have real evidence.
"""
type CustomerHealth {
  """GOOD at 70 and above, WATCH from 40 to 69, AT_RISK below 40."""
  band: String!
  """The frequency part."""
  frequency: Int!
  """
  Points taken off for warning signs in buying behavior, from 0 to 20. Empty when there is no app or checkout activity to judge.
  """
  intent: Int
  """The monetary part."""
  monetary: Int!
  """The payment part."""
  payment: Int!
  """Up to three plain reasons the score is not higher."""
  reasons: [String!]!
  """The recency part."""
  recency: Int!
  """
  The score from 0 to 100: recency plus frequency plus monetary plus payment, less intent.
  """
  score: Int!
}

"""One finding on the customer's attention list."""
type CustomerInsight {
  """The facts behind the finding."""
  evidence: [CustomerEvidence!]!
  """One plain sentence with the numbers in it."""
  headline: String!
  """
  The stable ID of the rule that found it, for example reorder_overdue or payment_drift.
  """
  key: String!
  """The rule in one line, so a reader sees why it fired."""
  ruleText: String!
  """INFO, GOOD, WARN or BAD."""
  severity: String!
  """
  The money at stake in the base currency. Empty when the finding has none.
  """
  stake: Float
}

"""
The customer's analytics, behind the Insights tab of the partner record.
"""
type CustomerInsights {
  """Buying rhythm."""
  cadence: CustomerCadence!
  """Invoiced value by top-level category."""
  categories: [CustomerCategoryRow!]!
  """Credit position."""
  credit: CustomerCredit!
  """The current non-tier discount. Empty when none applies."""
  discount: CustomerDiscountSnapshot
  """App and portal engagement."""
  engagement: CustomerEngagementFacts!
  """The health score. Empty unless all four parts have evidence."""
  health: CustomerHealth
  """
  The attention list, most severe first. Empty for a customer none of the rules describes.
  """
  insights: [CustomerInsight!]!
  """The one thing to do first. Empty when nothing needs attention."""
  nextBestAction: CustomerNextBestAction
  "The ID of the partner."
  partnerId: ID!
  """Payment behavior."""
  payments: CustomerPayments!
  """The top 5 products by invoiced value in the period."""
  products: [CustomerProductRow!]!
  """Quotes."""
  quotes: CustomerQuotes!
  """The period the figures cover."""
  range: CustomerInsightsRange!
  """Returns."""
  returns: CustomerReturns!
  """Spend."""
  spend: CustomerSpend!
  """The customer's tier. Empty when the organization has no tier ladder."""
  tier: CustomerTierSnapshot
  """Eligible schemes the customer never used."""
  unusedDiscounts: [CustomerUnusedDiscount!]!
}

"""The period an Insights payload covers, and the equal period before it."""
type CustomerInsightsRange {
  """
  The start of the comparison period: the equal-length period just before this one.
  """
  comparisonFrom: DateTime!
  """
  The end of the comparison period. It equals the start of the period and is exclusive.
  """
  comparisonTo: DateTime!
  """The start of the period."""
  from: DateTime!
  """The end of the period."""
  to: DateTime!
}

"""Invites a person to the customer's team."""
input CustomerInviteTeamMemberInput {
  """granted branch address ids (required ≥1 when scope = BRANCH)."""
  approverBranchAddressIds: [ID!]
  """
  Addresses this teammate may order to, chosen at INVITE time. Omit or [] leaves them unrestricted (the whole account address book) — it does NOT lock them out. Applied only to a genuinely new invite; the uniform anti-enumeration response assigns nothing.
  """
  assignedAddressIds: [ID!]
  """approver scope — COMPANY | BRANCH (default COMPANY)."""
  customerApproverScope: String
  """The person's department."""
  department: String
  "Email address."
  email: String!
  """The person's first name."""
  firstName: String
  """The person's last name."""
  lastName: String
  """Per-buyer order-value ceiling (null = no limit)."""
  orderLimit: Float
  "Phone number."
  phone: String
  """CUSTOMER_ADMIN | CUSTOMER_BUYER | CUSTOMER_VIEWER."""
  role: String!
  """The person's job title."""
  title: String
  """The person's WhatsApp number."""
  whatsapp: String
}

"""
One of the signed-in customer's invoices in the portal list, with its totals, balance due and due date.
"""
type CustomerInvoice {
  """The amount still owed."""
  balanceDue: Float!
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String
  """
  The permanent reference of the contact whose order produced the invoice. Hidden when it does not apply.
  """
  customerReferenceId: String
  """The date the invoice is due."""
  dueDate: DateTime
  "The unique ID of this record."
  id: ID!
  """The invoice number."""
  invoiceNumber: String
  """
  True when money was already paid against this invoice's order and the seller has not applied it yet. The apps hide the pay option until it is applied, so the invoice is not paid twice.
  """
  orderMoneyNotApplied: Boolean!
  """The amount paid."""
  paidAmount: Float!
  """The number of the sales order the invoice came from."""
  salesOrderNumber: String
  """The status of the invoice."""
  status: String!
  """The invoice total."""
  totalAmount: Float!
}

"""
A page of the customer's invoices, with the total outstanding and paging details.
"""
type CustomerInvoiceConnection {
  """The invoices on this page."""
  items: [CustomerInvoice!]!
  """Where this page sits in the full result."""
  meta: PaginationMeta!
  """The total still owed on all open sales invoices, not just this page."""
  totalOutstanding: Float
}

"""Per-currency invoice KPI bucket (Σ rows == these tiles)."""
type CustomerInvoiceKpiBucket {
  "ISO 4217 currency code."
  currency: String!
  """
  LIFETIME total billed in this currency: Σ totalAmount of every ISSUED SALES_INVOICE (excludes DRAFT / CANCELLED / VOIDED — the shared NON_ISSUED_INVOICE_STATUSES list). Unlike the three figures above it counts fully-PAID invoices too: this is what was billed, not what is owed. Same population as the seller-side Partner 360 'Total Invoiced', so the two surfaces agree; it ignores any period filter the client applies to the invoice list.
  """
  invoicedTotal: Float!
  """The part that is not yet due."""
  notYetDue: Float!
  """The total still owed."""
  outstanding: Float!
  """The part that is past due."""
  overdue: Float!
}

"""Invoices-screen KPI tiles + server-computed available credit."""
type CustomerInvoiceSummary {
  """
  Server-computed: creditLimit − Σ open SALES-invoice outstanding. NULL when the customer's credit is unlimited (creditUnlimited) — never 0.
  """
  availableCredit: Float
  """The figures, one entry per currency."""
  buckets: [CustomerInvoiceKpiBucket!]!
  """The currency of the customer's credit."""
  creditCurrency: String!
  """
  False when the org runs with credit limits switched off. availableCredit is then 0 by convention, so clients hide credit UI on THIS flag rather than rendering a zero as 'no credit left'.
  """
  creditLimitEnabled: Boolean!
  """
  True when the customer has no credit limit (creditLimit <= 0 = unlimited) on an org that enforces limits. availableCredit is then null; clients show 'Unlimited' and never disable On account on it.
  """
  creditUnlimited: Boolean!
  """
  False when this buyer cannot order On account (their payment term was retired, or the tenant default is not a credit term). Clients hide the On account row on it; checkout refuses it with ON_ACCOUNT_UNAVAILABLE.
  """
  onAccountAvailable: Boolean!
}

"""
A customer's lifetime order, invoice and payment figures, worked out from the documents on every read and never stored.
"""
type CustomerLifetimeFacts {
  """When the figures were worked out."""
  asOf: DateTime!
  """
  The invoiced total divided by the issued invoice count. 0 when there are none.
  """
  averageInvoice: Float!
  """How many orders are waiting for payment."""
  awaitingPaymentOrderCount: Int!
  """How many orders were cancelled."""
  cancelledOrderCount: Int!
  """How many orders are drafts."""
  draftOrderCount: Int!
  """When the first order was placed."""
  firstOrderAt: DateTime
  """
  How many issued invoices make up the invoiced total. Drafts, cancelled and voided invoices are not counted.
  """
  invoiceCount: Int!
  """
  The revenue: the base currency total of issued sales invoices, leaving out cancelled, voided and draft ones.
  """
  invoicedTotal: Float!
  """When the last order was placed."""
  lastOrderAt: DateTime
  """The number of the last order."""
  lastOrderNumber: String
  """The total of the last order."""
  lastOrderTotal: Float
  """When the last payment was received."""
  lastPaymentAt: DateTime
  """How many committed orders there are: confirmed and every later state."""
  orderCount: Int!
  """How many orders there are in all, whatever their status."""
  totalOrderCount: Int!
}

"""One customer row in the customer report."""
type CustomerListItem {
  """The average order value."""
  averageOrderValue: Float!
  """How many days since the last order."""
  daysSinceLastOrder: Int!
  "Email address."
  email: String!
  """The date of the first order."""
  firstOrderDate: DateTime
  "The unique ID of this record."
  id: ID!
  """The date of the last order."""
  lastOrderDate: DateTime
  """The customer's lifetime value."""
  lifetimeValue: Float!
  """The name of the customer."""
  name: String!
  """What the customer still owes."""
  outstandingBalance: Float!
  """The share of orders that were repeat purchases, in percent."""
  repeatPurchaseRate: Float!
  """The status of the customer."""
  status: String!
  """How many orders the customer placed."""
  totalOrders: Int!
  """The revenue from the customer."""
  totalRevenue: Float!
  """The kind of customer."""
  type: String
}

"""
Why quotes were lost, grouped. The reason is free text that tenants write themselves.
"""
type CustomerLossReason {
  """The competitors named."""
  competitors: [String!]!
  """How many quotes were lost for it."""
  count: Int!
  """The reason."""
  reason: String!
}

"""
One calendar month of invoiced value, in the organization's business time zone.
"""
type CustomerMonthPoint {
  """The month, as YYYY-MM."""
  bucket: String!
  """
  True when the period ends inside this month, so the month is not yet complete.
  """
  partial: Boolean!
  """The invoiced value."""
  value: Float!
}

"""
A pointer to the top-ranked finding in the insights list, with the actions that fit it.
"""
type CustomerNextBestAction {
  """The actions that fit, best first."""
  actions: [String!]!
  """The key of the finding."""
  key: String!
  """3 to act today, 2 for a deadline or a debt, 1 for a trend."""
  urgency: Int!
}

"""An order as the customer sees it in a list."""
type CustomerOrder {
  """
  The ID of the branch the order was placed for. Empty for orders at the customer level.
  """
  branchAddressId: String
  """The name of that branch."""
  branchLabel: String
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String
  "The unique ID of this record."
  id: ID!
  """How many lines the order has."""
  itemCount: Int!
  """The order number."""
  orderNumber: String
  """The delivery address."""
  shippingAddress: String
  """The status of the order."""
  status: String!
  """The order total."""
  totalAmount: Float!
}

"""A page of order approval requests."""
type CustomerOrderApprovalConnection {
  """The approval requests on this page."""
  items: [CustomerOrderApprovalView!]!
  """Paging metadata."""
  meta: PaginationMeta!
}

"""
screen 14: an over-limit portal checkout parked for approval. No order exists until an approver says yes; approval replays the snapshot through the canonical checkout path with a fresh reprice.
"""
type CustomerOrderApprovalView {
  """
  The delivery address in full, resolved live from the snapshot's addressId so requests parked before this existed show it too. Null when the address has since been deleted.
  """
  addressFull: String
  """The label of the delivery address."""
  addressLabel: String
  """
  The buying company (Partner) this request belongs to — resolved live, not snapshotted.
  """
  companyName: String
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String!
  """When it was decided."""
  decidedAt: DateTime
  """The name of the person who decided."""
  decidedByName: String
  """Why it was declined."""
  declineReason: String
  """The delivery fee."""
  deliveryFee: Float
  """True when the delivery fee was waived."""
  deliveryFeeWaived: Boolean
  """
  Σ line discounts frozen at request time. Absent (not 0) on requests parked before discounts were snapshotted.
  """
  discountAmount: Float
  """
  TRUE when discountAmount was derived from today's prices rather than read from the snapshot (see CustomerApprovalLine.discountDerived).
  """
  discountDerived: Boolean
  """
  The TRUE pre-discount gross — the cart's own 'Subtotal' row. Never reconstruct it by adding the discount back onto the net subtotal: that re-rounds an already-rounded figure and drifts a cent (BUG-20260818).
  """
  grossSubtotal: Float
  "The unique ID of this record."
  id: ID!
  """
  The limit at request time — the requester's customerOrderLimit, or the branch orderLimit for OVER_BRANCH_LIMIT (display: "Over her R 20,000 limit").
  """
  limitAtRequest: Float
  """How many lines the order has."""
  lineCount: Int!
  """The lines of the order."""
  lines: [CustomerApprovalLine!]!
  """Buyer-supplied checkout note."""
  notes: String
  """CustomerPaymentMethod value at checkout, when recorded."""
  paymentMethod: String
  """Buyer-supplied PO number (free text)."""
  poNumber: String
  """
  Why it routed to approval: OVER_USER_LIMIT | OVER_CREDIT_LIMIT | OVER_BRANCH_LIMIT.
  """
  reason: String!
  """REQ-… (per-org sequence, minted server-side)."""
  requestNumber: String!
  """The ID of the person who asked for approval."""
  requestedById: ID!
  """The name of the person who asked for approval."""
  requestedByName: String!
  """The ID of the order that was placed once approved."""
  resultingOrderId: ID
  """The number of that order."""
  resultingOrderNumber: String
  """Pending | Approved | Declined (DESIGN-SPEC approvals vocabulary)."""
  status: String!
  """Net-of-discount taxable amount — the tax base, not the gross."""
  subtotal: Float
  """The tax on the order."""
  taxAmount: Float
  """
  The full tax base `taxAmount` was computed on — `subtotal + deliveryFee` (this bill has no INCLUSIVE-tax concept, unlike the mobile order/invoice bill). Distinct from `subtotal`, which excludes the delivery fee. Absent on requests parked before this was snapshotted.
  """
  taxableAmount: Float
  """The order total."""
  totalAmount: Float!
}

"""A page of orders."""
type CustomerOrderConnection {
  """The orders on this page."""
  items: [CustomerOrder!]!
  """Where this page sits in the full result."""
  meta: PaginationMeta!
}

"""An order as the customer sees it in full."""
type CustomerOrderDetail {
  """The billing address."""
  billingAddress: String
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String
  """The purchase order or reference the buyer gave at checkout."""
  customerPoNumber: String
  """
  The live delivery option chosen at checkout. Empty for flat-fee orders.
  """
  deliverySelection: CustomerDeliverySelection
  """The total discount across every line. 0 when none applies."""
  discountAmount: Float!
  "The unique ID of this record."
  id: ID!
  """
  The IDs of the issued sales invoices of the order. Drafts, cancelled and voided ones are left out.
  """
  invoiceIds: [ID!]
  """The lines of the order."""
  items: [CustomerOrderItem!]!
  """Notes on the order."""
  notes: String
  """The order number."""
  orderNumber: String
  """
  What the buyer still owes on the order: the outstanding on its issued sales invoices, or the order total while none is issued.
  """
  paymentOutstanding: Float
  """
  How much shipment tracking this customer gets on the portal (FULL when the store's setting does not apply to it). STATUS: show no shipment section (and no 'tracking will appear' line) — the order status alone.
  """
  shipmentTrackingLevel: CustomerTrackingLevel!
  """
  The outbound shipments, oldest first, with carrier, tracking, expected date and timeline. Never the seller's cost.
  """
  shipments: [CustomerShipment!]!
  """The delivery address."""
  shippingAddress: String
  """The delivery fee charged on the order."""
  shippingAmount: Float!
  """The status of the order."""
  status: String!
  """The order amount before discount and tax."""
  subtotal: Float!
  """The tax on the order."""
  taxAmount: Float!
  """The order total."""
  totalAmount: Float!
  "When the record was last changed."
  updatedAt: DateTime
}

"""Filters for the customer's order list."""
input CustomerOrderFilterInput {
  """
  Only orders placed for this branch. It narrows the list and is not a security boundary.
  """
  branchAddressId: String
  """Rows per page. Defaults to 20."""
  limit: Int! = 20
  """Page number, starting at 1. Defaults to 1."""
  page: Int! = 1
  """Text to search for."""
  search: String
  """Only orders in this status."""
  status: String
  """
  Only orders in one of these statuses. A status chip can cover several statuses.
  """
  statuses: [String!]
}

"""One line of an order."""
type CustomerOrderItem {
  """
  True when the buyer agreed that a substitute chosen by staff may ship if the item becomes unavailable.
  """
  acceptAlternativeIfUnavailable: Boolean!
  """The discount on the line. 0 when none applies."""
  discountAmount: Float!
  """The discount on the line, in percent. 0 when none applies."""
  discountPercent: Float!
  "The unique ID of this record."
  id: ID!
  """The line total."""
  lineTotal: Float!
  """The name of the product."""
  productName: String!
  """The quantity ordered."""
  quantity: Float!
  """The SKU of the variant."""
  sku: String
  """The tax on the line. 0 when tax-exempt."""
  taxAmount: Float!
  """The tax rate on the line, in percent. 0 when tax-exempt."""
  taxRate: Float!
  """The list price of one unit, before discount."""
  unitPrice: Float!
  """The unit of measure."""
  uom: String
  """The name of the variant, for example a model and colour."""
  variantName: String
}

"""One line to look up when a buyer pastes an order, by product code."""
input CustomerOrderLineQueryInput {
  """SKU or free-text product name from the pasted list."""
  code: String!
  """The quantity. Must be greater than zero."""
  quantity: Float!
  """Optional UOM token (e.g. "case")."""
  uom: String
}

"""
"Payment under review" overlay for an order: AWAITING_PAYMENT + a pending COLLECTION payment (derived, never a backend status).
"""
type CustomerOrderPaymentOverlay {
  """
  What the customer may still pay (total minus received, waiting transfers and draft entries); 0 when canPay is false.
  """
  amountToPay: Float!
  """
  True when the seller has taken in the whole order total (accepted or recorded). Apps show 'Payment approved'.
  """
  approved: Boolean!
  """
  True when the customer may pay this order now: payable status and something still unpaid and unclaimed.
  """
  canPay: Boolean!
  """The ID of the order."""
  orderId: ID!
  """The amount of a bank transfer registered and not yet confirmed."""
  pendingAmount: Float
  """What the seller has already taken in against the order."""
  receivedAmount: Float!
  """When the transfer was registered."""
  registeredAt: DateTime
  """True when the seller is checking the transfer."""
  underReview: Boolean!
}

"""Which page of a list to return."""
input CustomerPaginationInput {
  """Rows per page. Defaults to 20."""
  limit: Int! = 20
  """Page number, starting at 1. Defaults to 1."""
  page: Int! = 1
  """Text to search for."""
  search: String
}

"""One row of the partner's purchase history (Quick order tab)."""
type CustomerPastPurchase {
  "ISO 4217 currency code."
  currency: String
  """When the customer last ordered it."""
  lastOrderedAt: DateTime!
  """
  What the buyer was charged per unit on the most recent order line — the net price after the line's discount, in `currency` (historical, display-only; the cart reprices on add).
  """
  lastUnitPrice: Float!
  """The largest quantity for one line in this unit. Empty means no cap."""
  maxOrderQuantity: Float
  """
  The smallest quantity for one line in this unit. The stricter of the variant's minimum and the pack's own wins, as when an order is created.
  """
  minOrderQuantity: Float!
  """
  Quantities step by this, counted from 0. 1 or less means no whole-number step.
  """
  orderMultiple: Float!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The SKU of the variant."""
  sku: String
  """How many times the customer ordered it."""
  timesOrdered: Int!
  """The unit of measure."""
  uomCode: String
  "The ID of the unit of measure."
  uomId: ID!
  "The ID of the product variant."
  variantId: ID!
  """The variant's own label, such as model and colour."""
  variantName: String
}

"""A page of past purchases."""
type CustomerPastPurchaseConnection {
  """The past purchases on this page."""
  items: [CustomerPastPurchase!]!
  """Where this page sits in the full result."""
  meta: PaginationMeta!
}

"""A payment the customer made."""
type CustomerPayment {
  """The amount paid."""
  amount: Float!
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """How it was paid."""
  method: String!
  """The payment number."""
  paymentNumber: String
  """The payment reference."""
  referenceNumber: String
  """The status of the payment."""
  status: String!
}

"""A page of payments."""
type CustomerPaymentConnection {
  """The payments on this page."""
  items: [CustomerPayment!]!
  """Where this page sits in the full result."""
  meta: PaginationMeta!
}

"""
portal checkout payment method. EFT = bank transfer then register payment; ON_ACCOUNT = credit terms; GATEWAY = hosted checkout (order starts AWAITING_PAYMENT).
"""
enum CustomerPaymentMethod {
  """Pay by electronic funds transfer."""
  EFT
  """Pay online through a payment gateway."""
  GATEWAY
  """Charge to the customer's credit account."""
  ON_ACCOUNT
}

"""
How the customer pays: how long it takes against the terms agreed, and what is open now.
"""
type CustomerPayments {
  """The open receivable by age."""
  aging: [CustomerAgingBucket!]!
  """What the aging bands are built on: DUE_DATE or INVOICE_DATE."""
  agingBasis: String!
  """The same over the comparison period. Empty when nothing settled then."""
  comparisonWeightedDaysToPay: Float
  """Every invoice settled in the period, oldest first."""
  invoices: [CustomerSettledInvoice!]!
  """
  The days past due of the oldest overdue invoice. Empty when none is overdue.
  """
  oldestOverdueDays: Int
  """
  The share settled on time, in percent. Empty when nothing settled in the period.
  """
  onTimePct: Float
  """The open receivable at the end of the period, in the base currency."""
  outstanding: Float!
  """
  The part of the outstanding amount past its due date at the end of the period.
  """
  overdue: Float!
  """How many were settled after it."""
  paidLate: Int!
  """How many invoices were settled on or before their due date."""
  paidOnTime: Int!
  """The payment term code."""
  termsCode: String
  """
  The days of credit the customer's payment term allows in this organization.
  """
  termsDays: Int!
  """
  The customer's own days to collect, weighted by allocation, over the period.
  """
  weightedDaysToPay: Float!
}

"""
Result of customerPlaceOrderFromQuote — the sales order minted from an ACCEPTED quote.
"""
type CustomerPlaceOrderResult {
  """The ID of the order that was placed."""
  orderId: ID!
  """SO-… (per-org sequence, minted server-side)."""
  orderNumber: String!
}

"""A product as a buyer sees it in a list."""
type CustomerProduct {
  """IN_STOCK, LOW_STOCK or OUT_OF_STOCK."""
  availabilityState: String
  "The ID of the brand."
  brandId: ID
  """The name of the brand."""
  brandName: String
  """
  True when this row can be added to the cart. Clients should use this to allow adding, not work it out from inStock. It is true when stock is not tracked for the variant.
  """
  canAddToCart: Boolean
  """The names of the categories the product is in."""
  categories: [String!]
  """The codes of those categories, for navigation."""
  categoryCodes: [String!]
  """The IDs of those categories, in the same order as the codes."""
  categoryIds: [String!]
  """What the product is."""
  description: String
  """The discount, in percent."""
  discountPercentage: Float
  "The unique ID of this record."
  id: ID!
  """
  The URL of the main image. Empty when neither the variant nor the product has one.
  """
  imageUrl: String
  """True when the product is in stock."""
  inStock: Boolean!
  """True when the product is flagged vegetarian."""
  isVeg: Boolean
  """The expected days from order to delivery."""
  leadTimeDays: Float
  """The undiscounted list price."""
  listPrice: Float
  """The quantity at or below which the product shows as low stock."""
  lowStockCount: Float
  """
  The largest quantity for one line in the same unit. Empty means no cap, and 0 means the pack cannot be ordered.
  """
  maxOrderQty: Float
  """
  The smallest quantity for one line in the unit the row is priced in. The stricter of the variant's minimum and the pack's own wins.
  """
  minOrderQty: Float
  """The name of the product."""
  name: String!
  """
  Quantities step by this, counted from 0. 1 or less means no whole-number step.
  """
  orderMultiple: Float
  """The price before any discount."""
  originalPrice: Float
  """The label of the pack the price is for."""
  packLabel: String
  """The price the buyer pays."""
  price: Float
  """
  The price per base unit, worked out from the sales unit of measure, so bulk items can be compared.
  """
  pricePerUnit: Float
  """The price per base unit as a number."""
  pricePerUnitBase: Float
  """The price per unit as text for display."""
  pricePerUnitDisplay: String
  """The unit the price per unit is for."""
  pricePerUnitUom: String
  """The volume tier prices of the default variant."""
  prices: [CustomerVariantSlabPrice!]
  """
  The names of any active discount schemes applied at quantity 1, for a promotion badge.
  """
  promotionLabel: String
  """
  False when the organization hides stock labels, so no in-stock or out-of-stock label may be shown.
  """
  showStockLevels: Boolean
  """The SKU of the default variant."""
  sku: String
  """The unit of measure the price is for."""
  uom: String
  "The ID of the unit of measure."
  uomId: ID
  """
  How many active variants the product has, so a card can offer a variant picker.
  """
  variantCount: Float
  "The ID of the product variant."
  variantId: ID
  """The name of the default variant."""
  variantLabel: String
  """
  Every active variant with its own units of measure and discounted tier prices.
  """
  variants: [CustomerVariant!]
}

"""A page of products."""
type CustomerProductConnection {
  """The products on this page."""
  items: [CustomerProduct!]!
  """Where this page sits in the full result."""
  meta: PaginationMeta!
}

"""A product as a buyer sees it on its page."""
type CustomerProductDetail {
  "The ID of the brand."
  brandId: String
  """The name of the brand."""
  brandName: String
  """True when any variant can be added to the cart."""
  canAddToCart: Boolean
  """The names of the categories the product is in."""
  categories: [String!]
  """The codes of those categories, for finding similar products."""
  categoryCodes: [String!]
  "When the record was created."
  createdAt: DateTime!
  """What the product is."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The URLs of the product images."""
  imageUrls: [String!]
  """True when any variant is in stock."""
  inStock: Boolean!
  """The undiscounted list price."""
  listPrice: Float
  """The name of the product."""
  name: String!
  """False when the organization hides stock labels."""
  showStockLevels: Boolean
  """The lowest price among the variants."""
  startingPrice: Float
  """The unit of measure the product is priced in."""
  uom: String
  """The variants of the product."""
  variants: [CustomerVariant!]!
}

"""One attribute axis, such as Color or Model, with its reachable values."""
type CustomerProductFacetAttribute {
  """The raw attribute key. Pass it back in attributeFilters."""
  key: String!
  """The label to show."""
  label: String!
  """The values and how many products have each."""
  values: [CustomerProductFacetValue!]!
}

"""A brand and how many products it has."""
type CustomerProductFacetBrand {
  """How many products."""
  count: Int!
  "The unique ID of this record."
  id: ID!
  """The name of the brand."""
  name: String!
}

"""The lowest and highest value reachable."""
type CustomerProductFacetRange {
  """The highest value."""
  max: Float
  """The lowest value."""
  min: Float
}

"""One value of an attribute axis."""
type CustomerProductFacetValue {
  """How many products have it under the buyer's other filters."""
  count: Int!
  """The value."""
  value: String!
}

"""The filter choices for the current product list."""
type CustomerProductFacets {
  """The attribute axes, drawn from variant attributes."""
  attributes: [CustomerProductFacetAttribute!]!
  """The brands and how many products each has."""
  brands: [CustomerProductFacetBrand!]!
  """The range of minimum order quantities reachable."""
  moq: CustomerProductFacetRange!
  """The price range reachable."""
  price: CustomerProductFacetRange!
  """How many products match the current filters."""
  totalCount: Int!
  """How many matching products are flagged vegetarian."""
  vegCount: Int!
}

"""Filters and sorting for the product list."""
input CustomerProductFilterInput {
  "The ID of the address."
  addressId: String
  """
  Only products with variants that match these attributes. Several entries must all match.
  """
  attributeFilters: [AttributeFilterInput!]
  """Only products this partner has bought before."""
  boughtBefore: Boolean
  "The ID of the brand."
  brandId: String
  """
  Only products of these brands. It wins over a single brand ID when both are given.
  """
  brandIds: [String!]
  """Only products in the category with this code."""
  categoryCode: String
  "The ID of the category."
  categoryId: String
  """Only products with at least one variant in stock."""
  inStockOnly: Boolean
  """Rows per page. Defaults to 20."""
  limit: Int! = 20
  """
  Hide products whose smallest accepted minimum order quantity is above this.
  """
  moqMax: Float
  """Page number, starting at 1. Defaults to 1."""
  page: Int! = 1
  """Only products whose cheapest variant costs at most this."""
  priceMax: Float
  """Only products whose cheapest variant costs at least this."""
  priceMin: Float
  """Only these products. Ids of other organizations match nothing."""
  productIds: [ID!]
  """Text to search for."""
  search: String
  """The column to sort by."""
  sortBy: String
  """The sort direction."""
  sortOrder: String
  """Only products flagged vegetarian."""
  vegOnly: Boolean
}

"""
One product's share of the customer's invoiced value, using the saved line totals.
"""
type CustomerProductRow {
  """
  The same product's value in the comparison period. 0 when it was not bought.
  """
  comparisonValue: Float!
  """The name of the product."""
  name: String!
  "The ID of the product."
  productId: ID!
  """The quantity in base units, so packs and singles compare."""
  quantity: Float!
  """The SKU."""
  sku: String
  """The invoiced value."""
  value: Float!
  "The ID of the product variant."
  variantId: ID
}

"""
What a customer has bought of one product or variant, across their orders.
"""
type CustomerPurchaseHistoryItem {
  """When it was most recently ordered."""
  lastOrderedAt: DateTime!
  """Quantity on the most recent order."""
  lastQty: Float!
  """Unit price on the most recent order."""
  lastUnitPrice: Float!
  """The ID of the unit of measure on the most recent order."""
  lastUomId: ID
  """Number of orders containing it."""
  orderCount: Int!
  "The ID of the product."
  productId: ID!
  """Name of the product."""
  productName: String!
  """SKU of the product or variant."""
  sku: String
  """Total quantity ordered across those orders."""
  totalQty: Float!
  "The ID of the product variant."
  variantId: ID
  """Name of the product variant, if any."""
  variantName: String
}

"""A quote as the customer sees it."""
type CustomerQuote {
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String
  "The unique ID of this record."
  id: ID!
  """How many lines the quote has."""
  itemCount: Int!
  """The quote number."""
  quoteNumber: String
  """The status of the quote."""
  status: String!
  """The quote total."""
  totalAmount: Float!
  """The date the quote is valid until."""
  validUntil: DateTime
}

"""A page of quotes."""
type CustomerQuoteConnection {
  """The quotes on this page."""
  items: [CustomerQuote!]!
  """Where this page sits in the full result."""
  meta: PaginationMeta!
}

"""Full portal-facing quote detail. screen 13."""
type CustomerQuoteDetail {
  """
  Set when the quote has been converted to a sales order — by staff (convertToSalesOrder) or by the buyer (customerPlaceOrderFromQuote); both run the ONE staff conversion path.
  """
  convertedToSalesOrderId: ID
  "ISO 4217 currency code."
  currency: String!
  """The total discount across every line. 0 when none applies."""
  discountAmount: Float!
  "The unique ID of this record."
  id: ID!
  """The lines of the quote."""
  items: [CustomerQuoteLine!]!
  """Notes on the quote."""
  notes: String
  """The date of the quote."""
  quoteDate: DateTime!
  """The quote number."""
  quoteNumber: String!
  """Buyer's own PO / reference."""
  reference: String
  """The seller's shipping charge. 0 when none."""
  shippingAmount: Float!
  """Backend Quote status; errors on accept: QUOTE_NOT_ACCEPTABLE."""
  status: String!
  """The quote amount before discount and tax."""
  subtotal: Float!
  """The tax on the quote."""
  taxAmount: Float!
  """The quote total."""
  totalAmount: Float!
  """The date the quote is valid until."""
  validUntil: DateTime!
}

"""Paging, search and status filters for the customer's quotes."""
input CustomerQuoteFilterInput {
  """Rows per page. Defaults to 20."""
  limit: Int! = 20
  """Page number, starting at 1. Defaults to 1."""
  page: Int! = 1
  """Text to search for."""
  search: String
  """
  Only quotes in these statuses. A status chip can cover several; for example Accepted covers ACCEPTED, APPROVED and CONVERTED.
  """
  statuses: [String!]
}

"""One line of a quote."""
type CustomerQuoteLine {
  "The unique ID of this record."
  id: ID!
  """The line total."""
  lineTotal: Float!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The quantity."""
  quantity: Float!
  """The SKU of the variant."""
  sku: String
  """The tax on the line."""
  taxAmount: Float!
  """The tax rate on the line, in percent."""
  taxRate: Float!
  """Frozen engine price — resolved by LinePricingService at request time."""
  unitPrice: Float!
  """The unit of measure."""
  uomCode: String
  "The ID of the unit of measure."
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
  """The name of the variant, for example a model and colour."""
  variantName: String
}

"""Result of turning the current cart into a quote request. screen 13."""
type CustomerQuoteRequestResult {
  "ISO 4217 currency code."
  currency: String!
  "The ID of the quote."
  quoteId: ID!
  """QT-… (per-org sequence, minted server-side)."""
  quoteNumber: String!
  """The total of the quote that was requested."""
  totalAmount: Float!
  """quoteDate + PortalConfiguration.quoteValidityDays."""
  validUntil: DateTime!
}

"""The customer's quotes."""
type CustomerQuotes {
  """
  The share of outbound emails opened, across quote and order emails. Empty when nothing was sent.
  """
  emailOpenRatePct: Float
  """Why quotes were lost."""
  lossReasons: [CustomerLossReason!]!
  """How many quotes were lost."""
  lost: Int!
  """The median days from quote to order."""
  medianQuoteToOrderDays: Float
  """How many quotes are open."""
  openCount: Int!
  """How many open quotes expire within a week."""
  openExpiring7d: Int!
  """The value of open quotes."""
  openValue: Float!
  """The quote funnel."""
  stages: [CustomerFunnelStage!]!
  """Won as a percent of won plus lost. Empty when nothing has closed."""
  winRatePct: Float
  """How many quotes were won."""
  won: Int!
}

"""Gets a new access token from a refresh token."""
input CustomerRefreshTokenInput {
  """The refresh token."""
  refreshToken: String!
}

"""
Registers a bank transfer the customer made, for the seller to confirm.
"""
input CustomerRegisterEftPaymentInput {
  """Amount transferred."""
  amount: Float!
  """Exactly one of orderId | invoiceId is required."""
  invoiceId: ID
  """Exactly one of orderId | invoiceId is required."""
  orderId: ID
  """Date of the transfer."""
  paymentDate: DateTime!
  """Bank reference / UTR the buyer used for the transfer."""
  referenceNumber: String!
}

"""
Whether a rep can send this reminder now, and if not why. It drives the disabled button and its reason.
"""
type CustomerReminderEligibilityGql {
  """True when the reminder can be sent."""
  allowed: Boolean!
  """
  When allowed but held to the next send window, such as after quiet hours, the time it will go out.
  """
  deferredUntil: DateTime
  """
  A machine-readable reason when it cannot be sent, for example NO_RECIPIENT, NOTHING_TO_REMIND, WHATSAPP_OFF or TEMPLATE_OFF.
  """
  reason: String
  """A plain reason to show next to the disabled action."""
  reasonText: String
}

"""Sends a reminder to one customer."""
input CustomerReminderInput {
  "The ID of the partner."
  partnerId: ID!
  """
  The finding the reminder is about: cart_idle, invoices_overdue or quotes_expiring.
  """
  signalKey: String!
}

"""What happened to one customer's reminder."""
type CustomerReminderOutcomeGql {
  """When it will go out, if it was held to the next send window."""
  deferredUntil: DateTime
  "The ID of the partner."
  partnerId: ID!
  """True when the reminder was queued."""
  queued: Boolean!
  """Why it was not sent, in plain language."""
  reasonText: String
}

"""The result of sending a reminder."""
type CustomerReminderResultGql {
  """When it will go out, if it was held to the next send window."""
  deferredUntil: DateTime
  """
  True when the reminder was queued. The sender checks again before it goes out.
  """
  queued: Boolean!
}

"""Sends a reminder to several customers."""
input CustomerRemindersInput {
  """The IDs of the customers."""
  partnerIds: [ID!]!
  """
  The finding the reminder is about: cart_idle, invoices_overdue or quotes_expiring.
  """
  signalKey: String!
}

"""The result of sending reminders to several customers."""
type CustomerRemindersResultGql {
  """What happened to each customer."""
  outcomes: [CustomerReminderOutcomeGql!]!
  """How many were queued."""
  sent: Int!
  """How many were skipped."""
  skipped: Int!
}

"""Filters for the customer reports."""
input CustomerReportFiltersInput {
  """The start of the period. Defaults to the last 365 days."""
  dateFrom: String
  """The end of the period."""
  dateTo: String
  "Text to search for."
  search: String
  """Only customers in this status."""
  status: String
  """Only customers of this kind."""
  type: String
}

"""The customer reports."""
type CustomerReportsData {
  """How customers who joined in each period behave over time."""
  cohortAnalysis: [CohortAnalysis!]!
  """One row per customer."""
  customerList: [CustomerListItem!]!
  """The customer segments."""
  customerSegments: [CustomerAnalyticsSegment!]!
  """Headline figures."""
  summary: CustomerReportsSummary!
  """The customers who bring in the most revenue."""
  topCustomers: [CustomerTopCustomerRevenue!]!
}

"""Headline figures of the customer reports."""
type CustomerReportsSummary {
  """How many are active."""
  activeCustomers: Int!
  """The average customer lifetime value."""
  averageLifetimeValue: Float!
  """The average order value."""
  averageOrderValue: Float!
  """How many stopped buying."""
  churnedCustomers: Int!
  """How many joined in the period."""
  newCustomers: Int!
  """The share of customers who bought more than once, in percent."""
  repeatCustomerRate: Float!
  """How many customers there are."""
  totalCustomers: Int!
  """The total revenue."""
  totalRevenue: Float!
}

"""The details of a quote request made from the cart."""
input CustomerRequestQuoteInput {
  """CAS guard: the cart revision this request was read against."""
  expectedRevision: Int
  """
  Idempotency key — forwarded into QuotesService.create so a retried request replays the original quote.
  """
  idempotencyKey: String
  """Notes for the seller about this quote request."""
  notes: String
  """Buyer's own PO / reference for this quote request."""
  reference: String
}

"""Pasted order lines to match to products."""
input CustomerResolveOrderLinesInput {
  """The lines to look up."""
  lines: [CustomerOrderLineQueryInput!]!
}

"""A pasted line resolved to a purchasable variant, repriced server-side."""
type CustomerResolvedLine {
  """The code that was pasted."""
  inputCode: String!
  """The line total."""
  lineTotal: Float!
  """SKU_EXACT | BARCODE_EXACT | NAME_FUZZY | VARIANT_NAME_FUZZY."""
  matchKind: String!
  """The largest quantity for one line in this unit. Empty means no cap."""
  maxOrderQuantity: Float
  """
  The smallest quantity for one line in this unit. The stricter of the variant's minimum and the pack's own wins, as when an order is created.
  """
  minOrderQuantity: Float!
  """
  False when `quantity` violates the effective minimum/maximum/step for this variant+uom (same rule Add-to-cart enforces).
  """
  moqValid: Boolean!
  """
  Quantities step by this, counted from 0. 1 or less means no whole-number step.
  """
  orderMultiple: Float!
  "The ID of the product."
  productId: ID!
  """The name of the product it matched."""
  productName: String!
  """The quantity."""
  quantity: Float!
  """The SKU of the variant it matched."""
  sku: String!
  """The price of one unit."""
  unitPrice: Float!
  "The ID of the unit of measure."
  uomId: ID!
  """False when the requested UOM token did not match a sellable UOM."""
  uomValid: Boolean!
  "The ID of the product variant."
  variantId: ID!
}

"""The result of matching pasted order lines."""
type CustomerResolvedOrderLines {
  """The lines that matched a product."""
  resolved: [CustomerResolvedLine!]!
  """The lines that matched nothing."""
  unresolved: [CustomerUnresolvedLine!]!
}

"""A page of returns."""
type CustomerReturnConnection {
  """The returns on this page."""
  items: [CustomerReturnView!]!
  """Where this page sits in the full result."""
  meta: PaginationMeta!
}

"""One line to return."""
input CustomerReturnLineInput {
  """The ID of the order line."""
  orderItemId: ID!
  """The quantity to return. Must be greater than zero."""
  quantity: Float!
}

"""One reason goods came back."""
type CustomerReturnReason {
  """How many returns."""
  count: Int!
  """The reason."""
  reason: String!
  """Their value."""
  value: Float!
}

"""
Portal-facing return view. Status: Requested | Collected | Credit note issued.
"""
type CustomerReturnView {
  "When the record was created."
  createdAt: DateTime!
  """Set once the credit note is issued."""
  creditNoteNumber: String
  "The unique ID of this record."
  id: ID!
  """Human summary, e.g. "2 × ZZ E2E Widget"."""
  itemsSummary: String!
  """The ID of the order."""
  orderId: ID
  """The number of the order."""
  orderNumber: String
  """
  courier pickups booked for this return (oldest first) — status, carrier, tracking (https link only) and timeline. Empty when no pickup was booked.
  """
  pickupShipments: [CustomerShipment!]!
  """
  Backend truth ('PENDING' | 'PROCESSED' | …) — for debugging; FE renders `status`.
  """
  rawStatus: String!
  """Why the goods are returned."""
  reason: String!
  """Internal return number."""
  returnNumber: String!
  """RMA-… shown in the UI (minted server-side)."""
  rmaNumber: String
  """
  Requested | Collected | Credit note issued (DESIGN-SPEC returns vocabulary).
  """
  status: String!
}

"""
A delivered order line the buyer may still return (within returnsWindowDays).
"""
type CustomerReturnableLine {
  """The ID of the order line."""
  orderItemId: ID!
  """The name of the product."""
  productName: String!
  """
  Σ quantity across this line's prior non-cancelled returns — max returnable = quantityDelivered − this.
  """
  quantityAlreadyReturned: Float!
  """The quantity delivered."""
  quantityDelivered: Float!
  """The SKU of the variant."""
  sku: String
  """The unit of measure."""
  uomCode: String
}

"""A delivered order still inside the returns window. screen 15."""
type CustomerReturnableOrder {
  """The date the order was delivered."""
  deliveredDate: DateTime!
  """The lines that can be returned."""
  lines: [CustomerReturnableLine!]!
  """The ID of the order."""
  orderId: ID!
  """The number of the order."""
  orderNumber: String!
  """deliveredDate + PortalConfiguration.returnsWindowDays."""
  windowClosesAt: DateTime!
}

"""
The customer's product returns, over the same population as the Returns report.
"""
type CustomerReturns {
  """
  The average satisfaction rating where one was recorded. Empty when none was.
  """
  avgSatisfaction: Float
  """How many returns there were."""
  count: Int!
  """
  The return value as a percent of spend. Empty when nothing was invoiced.
  """
  ratePct: Float
  """Why goods came back."""
  reasons: [CustomerReturnReason!]!
  """The value of the returns in the period, in the base currency."""
  value: Float!
}

"""A group of customers."""
type CustomerSegment {
  """The average order value in the segment."""
  averageOrderValue: Float!
  """How many customers are in it."""
  count: Int!
  """The revenue from the segment."""
  revenue: Float!
  """The name of the segment."""
  segment: String!
}

"""
One invoice the customer settled within the period, and how long settlement took.
"""
type CustomerSettledInvoice {
  """
  The value allocated to the invoice inside the period, in the base currency.
  """
  amount: Float!
  """
  The days from the invoice date to the money landing, weighted by allocation.
  """
  days: Float!
  """The date the invoice was due."""
  dueDate: DateTime!
  """The date of the invoice."""
  invoiceDate: DateTime!
  "The ID of the invoice."
  invoiceId: ID!
  """The invoice number."""
  invoiceNumber: String!
  """True when it was settled after its own due date."""
  late: Boolean!
  """When the last in-period allocation landed."""
  settledAt: DateTime
}

"""
A shipment as the buyer sees it: status, carrier, tracking and timeline. Never carries the seller's cost, provider ids or provider errors. Under the store's "progress only" tracking the courier, service, logo, tracking number, link and live position are null/false and `events` holds dated milestones only; under "order status only" no shipment is returned at all.
"""
type CustomerShipment {
  """
  The courier's logo (an image URL or PNG data URI), or null — show the carrier name alone.
  """
  carrierLogoUrl: String
  """
  The courier, or null when the store does not show it to customers (progress-only tracking).
  """
  carrierName: String
  """When the shipment was delivered."""
  deliveredAt: DateTime
  """When the shipment is expected to arrive."""
  estimatedDeliveryAt: DateTime
  """Oldest first."""
  events: [CustomerShipmentEvent!]!
  "The unique ID of this record."
  id: ID!
  """
  True while a courier is carrying this shipment (PICKED_UP / OUT_FOR_DELIVERY) and its carrier reports a live courier position. Read the position with customerShipmentLiveLocation (portal) or mobileShipmentLiveLocation (buyer app); it can still be null when the carrier has none at that moment.
  """
  liveLocationAvailable: Boolean!
  """The name of the service level."""
  serviceLevelName: String
  """The shipment number."""
  shipmentNumber: String!
  """The status of the shipment."""
  status: ShipmentStatus!
  """The carrier's tracking number."""
  trackingNumber: String
  """
  The carrier's public tracking page. https only — any other link is dropped (null).
  """
  trackingUrl: String
}

"""
One point on a shipment's tracking timeline, as the buyer sees it. `description` and `location` are the carrier's own words; staff notes are never included.
"""
type CustomerShipmentEvent {
  """What happened."""
  description: String
  """Where it happened."""
  location: String
  """When it happened."""
  occurredAt: DateTime!
  """The status of the shipment at this point."""
  status: ShipmentStatus!
}

"""
A buyer's tracking view of one of their shipments: the shipment, its progress steps, any problem it is in, and when the carrier was last asked. Never carries the carrier's error text.
"""
type CustomerShipmentTracking {
  """
  True when the carrier can be asked for news (offer Refresh). False for custom couriers and finished shipments.
  """
  canAskCarrier: Boolean!
  """
  When the carrier was last asked for news (null when it has not been, or cannot be).
  """
  checkedAt: DateTime
  """
  Set while the shipment is in trouble (failed attempt, exception, returned, lost); the stepper keeps the last reached step CURRENT.
  """
  problemStatus: ShipmentStatus
  """
  BOOKED, PICKED_UP, IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERED — in that order.
  """
  progress: [ShipmentProgressStep!]!
  """The shipment as the customer sees it."""
  shipment: CustomerShipment!
  """
  True when the last ask to the carrier failed — show the saved updates with a quiet note.
  """
  updateDelayed: Boolean!
}

"""The customer's spend."""
type CustomerSpend {
  """
  The committed order value divided by the committed order count. 0 when there are none.
  """
  avgOrder: Float!
  """Invoiced value by month. The months add up to the total."""
  byMonth: [CustomerMonthPoint!]!
  """
  The change against the comparison period, in percent. Empty when that period is empty.
  """
  changePct: Float
  """The average order value in the comparison period."""
  comparisonAvgOrder: Float!
  """How many committed orders there were in the comparison period."""
  comparisonOrderCount: Int!
  """The value of the committed orders in the comparison period."""
  comparisonOrderValue: Float!
  """The same total over the comparison period."""
  comparisonTotal: Float!
  """How many committed orders there were in the period."""
  orderCount: Int!
  """
  The value of the committed orders in the period, in the base currency. The average order is this divided by the order count; it differs from the invoiced total by whatever is ordered but not yet invoiced.
  """
  orderValue: Float!
  """
  The total of issued sales invoices in the period, in the base currency. This is invoiced value; the value of the orders placed in the period is orderValue.
  """
  total: Float!
}

"""Customer account statement over a date window. screen 11."""
type CustomerStatement {
  """The start of the period."""
  from: DateTime!
  """The statement sections, one per currency."""
  sections: [CustomerStatementSection!]!
  """The end of the period."""
  to: DateTime!
}

"""One statement line."""
type CustomerStatementRow {
  """Running balance after this row."""
  balance: Float!
  """The amount credited."""
  credit: Float!
  """The date of the entry."""
  date: DateTime!
  """The amount charged."""
  debit: Float!
  """INVOICE | PAYMENT | CREDIT_NOTE."""
  kind: String!
  """Document number (INV-… / PAY-… / CN-…)."""
  number: String!
  """The number of the document."""
  reference: String
}

"""
Per-currency statement section: openingBalance + Σ debits − Σ credits == closingBalance.
"""
type CustomerStatementSection {
  """The balance at the end of the period."""
  closingBalance: Float!
  "ISO 4217 currency code."
  currency: String!
  """The balance at the start of the period."""
  openingBalance: Float!
  """The entries in the period."""
  rows: [CustomerStatementRow!]!
}

"""Headline customer statistics."""
type CustomerStatistics {
  """How many are active."""
  activeCustomers: Int!
  """The average order value."""
  averageOrderValue: Float!
  """The customers who spend the most."""
  topCustomers: [CustomerTopCustomer!]!
  """How many customers there are."""
  totalCustomers: Int!
  """The total sales amount."""
  totalSalesAmount: Float!
}

"""
A customer's tax exemption as the record edits it. Every field is replaced as sent, and null clears it.
"""
input CustomerTaxExemptionInput {
  """The number of the exemption certificate."""
  certificateNumber: String
  """Why the customer is exempt from tax."""
  reason: String
  """True when the customer is exempt from tax."""
  taxExempt: Boolean!
  """
  The first day the exemption is valid, as YYYY-MM-DD. Null means open-ended.
  """
  validFrom: String
  """
  The last day the exemption is valid, as YYYY-MM-DD. Null means open-ended.
  """
  validTo: String
}

"""
One buyer-side team member (a CUSTOMER-userType User under this partner).
"""
type CustomerTeamMember {
  """May approve teammates' over-limit order requests (screen 14)."""
  approvesOrders: Boolean!
  """
  Addresses assigned to this member by the account owner. EMPTY means unrestricted — the member sees the whole account address book — NOT that they have none. A non-empty list confines them to exactly those addresses and hides their add/edit address controls.
  """
  assignedAddressIds: [ID!]!
  """Contact.department."""
  department: String
  "Email address."
  email: String!
  """The person's first name."""
  firstName: String!
  """
  PENDING (invited, not yet accepted) | ACTIVE (accepted + enabled) | DEACTIVATED (accepted, access revoked). Only a DEACTIVATED member can be reactivated.
  """
  inviteStatus: String!
  """The person's last name."""
  lastName: String!
  """Per-buyer order-value ceiling (org base currency; null = no limit).."""
  orderLimit: Float
  """User.phone, falling back to the person's PHONE contact row."""
  phone: String
  """
  The member's permanent contact reference (Contact.referenceId, e.g. C000110-a3f91b7e). Absent when no contact row carries one — a partner with no code, a login invited with no contact ever filed, or a row predating the backfill. Clients render nothing rather than a placeholder.
  """
  referenceId: String
  """CUSTOMER_ADMIN | CUSTOMER_BUYER | CUSTOMER_VIEWER."""
  role: String!
  """ACTIVE | INACTIVE — the raw User.status."""
  status: String!
  """Contact.contactTitle — job title."""
  title: String
  "The ID of the user."
  userId: ID!
  """The person's WHATSAPP contact row value."""
  whatsapp: String
}

"""One customer tier's figures."""
type CustomerTierAnalytics {
  """How many customers are in it."""
  count: Int!
  """The revenue from them."""
  revenue: Float!
  """The tier."""
  tier: String!
}

"""The customer discount tier setup."""
type CustomerTierConfig {
  """False when automatic tiering is off. Manual overrides still apply."""
  enabled: Boolean!
  """
  False when the tier module is off, so no tier is shown, charged or assigned anywhere.
  """
  moduleEnabled: Boolean!
  """The tiers, from lowest to highest."""
  tiers: [CustomerTierConfigItem!]!
}

"""
One rung of the customer discount tier ladder. The keys are fixed: SILVER, GOLD, PLATINUM and DIAMOND.
"""
type CustomerTierConfigItem {
  """
  The ID of the discount scheme given to customers in the tier. Empty means no discount.
  """
  discountSchemeId: String
  "Whether this is the default."
  isDefault: Boolean!
  """The key of the tier."""
  key: String!
  """The name of the tier."""
  name: String!
  """The position in the ladder, from the threshold. 0 is the lowest."""
  rank: Int!
  """
  The order value this month at or above which a customer reaches the tier.
  """
  threshold: Float!
}

"""One tier to save."""
input CustomerTierConfigItemInput {
  """
  The ID of the discount scheme given to customers in the tier. Empty means no discount.
  """
  discountSchemeId: String
  "Whether this is the default."
  isDefault: Boolean! = false
  """
  The key of the tier. Leave out for a new tier, and the server assigns one.
  """
  key: String
  """The name of the tier."""
  name: String!
  """
  The order value this month at or above which a customer reaches the tier.
  """
  threshold: Float!
}

"""The customer's tier."""
type CustomerTierSnapshot {
  """True when the organization's automatic tiering is on."""
  autoTieringEnabled: Boolean!
  """The days left in the current calendar month."""
  daysLeftInMonth: Int!
  "Whether this is the default."
  isDefault: Boolean!
  """
  True when the tier is pinned by hand and automatic tiering will not move it.
  """
  locked: Boolean!
  """
  This calendar month's committed spend, including orders awaiting payment.
  """
  monthlySpend: Float!
  """The next tier's discount in percent."""
  nextTierDiscountPct: Float
  """The key of the next tier up. Empty at the top."""
  nextTierKey: String
  """The name of the next tier up."""
  nextTierName: String
  """The spend at which the next tier starts."""
  nextTierThreshold: Float
  """
  How much more the customer must spend this month to reach the next tier.
  """
  remainingToNextTier: Float
  """
  The tier's discount in percent. 0 for a non-percentage or unmapped scheme.
  """
  tierDiscountPct: Float!
  """The key of the tier."""
  tierKey: String!
  """The name of the tier."""
  tierName: String!
  """The spend at which the tier starts."""
  tierThreshold: Float!
}

"""A customer's tier status after a manual override."""
type CustomerTierStatus {
  "The ID of the customer."
  customerId: String!
  """The key of the tier."""
  customerTier: String
  """
  True when the tier is pinned by hand and automatic tiering will not move it.
  """
  locked: Boolean!
}

"""A top customer by orders."""
type CustomerTopCustomer {
  "The unique ID of this record."
  id: ID!
  """The date of the last order."""
  lastOrderDate: DateTime
  """The name of the customer."""
  name: String!
  """The total amount ordered."""
  totalAmount: Float!
  """How many orders the customer placed."""
  totalOrders: Int!
}

"""A top customer by revenue."""
type CustomerTopCustomerRevenue {
  """The average order value."""
  averageOrderValue: Float!
  "The ID of the customer."
  customerId: ID!
  """The name of the customer."""
  customerName: String!
  """How many orders the customer placed."""
  totalOrders: Int!
  """The revenue from the customer."""
  totalRevenue: Float!
}

"""
FULL: courier, number, events and link. PROGRESS: dated milestones only. STATUS: no shipment section.
"""
enum CustomerTrackingLevel {
  """Courier, tracking number, events and link."""
  FULL
  """Dated milestones only."""
  PROGRESS
  """No shipment section."""
  STATUS
}

"""A pasted line that matched no product."""
type CustomerUnresolvedLine {
  """The code that was pasted."""
  inputCode: String!
  """NOT_FOUND | AMBIGUOUS | OUT_OF_CATALOG."""
  reason: String!
}

"""
An eligible non-tier discount scheme the customer never used on an order.
"""
type CustomerUnusedDiscount {
  """Whole days the scheme has been live, to the end of the period."""
  daysLive: Int!
  """The fixed discount amount."""
  fixedAmountValue: Float
  "The unique ID of this record."
  id: String!
  """The name of the scheme."""
  name: String!
  """The discount in percent."""
  percentageValue: Float
}

"""Changes the quantity of an item on a buying list."""
input CustomerUpdateBuyingListItemInput {
  """The ID of the item."""
  itemId: ID!
  """The ID of the buying list."""
  listId: ID!
  """
  The new quantity. It replaces the saved one. Must be greater than zero.
  """
  quantity: Float!
  """Move the line to a different pack. Omitted leaves the pack as it is."""
  uomId: ID
}

"""Changes to a team member. Omitted fields stay as they are."""
input CustomerUpdateTeamMemberInput {
  """granted branch address ids (required ≥1 when scope = BRANCH)."""
  approverBranchAddressIds: [ID!]
  """True when the person approves orders."""
  approvesOrders: Boolean
  """approver scope — COMPANY | BRANCH."""
  customerApproverScope: String
  """The person's department."""
  department: String
  """The person's first name."""
  firstName: String
  """The person's last name."""
  lastName: String
  """The largest order the person may approve or place."""
  orderLimit: Float
  "Phone number."
  phone: String
  """CUSTOMER_ADMIN | CUSTOMER_BUYER | CUSTOMER_VIEWER."""
  role: String
  """The person's job title."""
  title: String
  "The ID of the user."
  userId: ID!
  """The person's WhatsApp number."""
  whatsapp: String
}

"""The signed-in customer user's own profile."""
type CustomerUser {
  """The URL of the person's picture."""
  avatar: String
  "Email address."
  email: String!
  """The person's first name."""
  firstName: String!
  "The unique ID of this record."
  id: ID!
  """The person's last name."""
  lastName: String!
  "The ID of the organization the record belongs to."
  organizationId: ID!
  "The ID of the partner."
  partnerId: ID!
  """The name of the customer account the person belongs to."""
  partnerName: String!
  """The person's role in the customer account."""
  role: String!
  """User type: STAFF or CUSTOMER"""
  userType: String!
}

"""
One address of the customer account, flagged with what this user holds on it. It lists every live address, not just the assigned ones.
"""
type CustomerUserAddressAssignment {
  "The unique ID of this record."
  id: ID!
  """Address.isActive — an inactive address is un-orderable."""
  isActive: Boolean!
  """
  PartnerBranchApprover row exists ⇒ this user may decide approval requests parked for this branch. Only ever set when approverScope = BRANCH.
  """
  isApprover: Boolean!
  """
  PartnerBranchMember row exists ⇒ this address is assigned to the user: they may order FOR it and see its orders (visibility-scope rule 3). NOTE the whole-list rule — NO assigned address means unrestricted (the user sees every address), never none.
  """
  isAssigned: Boolean!
  """
  Address.isBranch — whether this address is also a sales branch. Assignment does NOT require it; it gates the branch-only extras below.
  """
  isBranch: Boolean!
  """Address.label."""
  label: String
  """
  The ADDRESS's own order ceiling — not the user's. Branch rows only; null = no limit.
  """
  orderLimit: Float
  """
  One-line 'street, city' summary — an unlabelled address is otherwise an unreadable row of uuids in the assignment picker.
  """
  summary: String
  """Address.type — BILLING | SHIPPING | …"""
  type: String
}

"""A variant of a product as a buyer sees it."""
type CustomerVariant {
  """The QR code of the variant."""
  QRCode: String
  """The variant's attributes, such as colour or size, as JSON text."""
  attributes: String
  """The quantity available."""
  availableQuantity: Float!
  """The barcode of the variant."""
  barcode: String
  """True when the variant can be added to the cart."""
  canAddToCart: Boolean
  """JSON-stringified { length?, width?, height? }"""
  dimensions: String
  "The unique ID of this record."
  id: ID!
  """The URLs of the variant images."""
  imageUrls: [String!]
  """True when the variant is in stock."""
  inStock: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """The largest quantity that can be ordered."""
  maxOrderQuantity: Float
  """The smallest quantity that can be ordered."""
  minOrderQuantity: Float!
  """The name of the variant."""
  name: String
  """The price the buyer pays."""
  price: Float
  """The volume tier prices."""
  prices: [CustomerVariantSlabPrice!]
  """The sale price."""
  salePrice: Float
  """False when the organization hides stock labels."""
  showStockLevels: Boolean
  """The SKU of the variant."""
  sku: String!
  """The unit of measure."""
  uom: String
  "The ID of the unit of measure."
  uomId: ID
  """The units of measure the variant is sold in."""
  uoms: [ProductUOMType!]
  """The weight of one unit."""
  weight: Float
}

"""
The resolved single price for a variant (per selected UOM + qty), plus automatic-discount breakdown and the P1d line-pricing exposure.
"""
type CustomerVariantPrice {
  """Breakdown of applied automatic discount schemes"""
  appliedDiscounts: [DiscountDetail!]
  """Discount amount per unit from automatic discount schemes"""
  automaticDiscountAmount: Float
  """Total automatic discount percentage (e.g. 5 for VIP_DISCOUNT)"""
  automaticDiscountPercent: Float
  """
  The rate a converted price used, 1 {document currency} = rate {base}. Null unless priceConverted.
  """
  convertedAtRate: Float
  """
  The exact base-currency unit price (per selected UOM) a converted price came from. Null unless priceConverted.
  """
  convertedFromBaseUnitPrice: Float
  """
  ISO code the returned price is denominated in (document currency when requested, else org base).
  """
  currencyCode: String
  """The customer's effective tier key (e.g. GOLD)."""
  customerTier: String
  """
  The effective tier's current name. Render this, never the key — a rename changes the name and not the key.
  """
  customerTierName: String
  """Unit price after automatic discounts."""
  finalPrice: Float
  """True when the canonical waterfall resolved a price for this variant."""
  found: Boolean!
  """Discount % from global schemes."""
  globalDiscountPercentage: Float
  """
  Reference list/MRP per SELECTED UOM (strike-through anchor) from the canonical line-pricing engine — max(uomListPrice, variantPrice×cf, highestTier, baseUnitPrice). 0/null when noPriceInCurrency.
  """
  listUnitPrice: Float
  """
  True when a foreign document currency was requested — every price is base-denominated, so the line is un-priceable (never currency-converted). False in base/legacy mode.
  """
  noPriceInCurrency: Boolean!
  """Unit price before automatic discounts."""
  originalPrice: Float
  """Sellable UOM pack options (uom + conversion + price) (P1d)."""
  packOptions: [LinePackOption!]
  """Final unit price after automatic discounts"""
  priceAfterDiscount: Float
  """
  True when the price was produced by CONVERTING the base price at convertedAtRate: the document currency had no price of its own and the caller opted in with convertAtRate. Absent otherwise.
  """
  priceConverted: Boolean
  """
  Order qty rules (min / max / order multiple) for the selected UOM (P1d).
  """
  qtyRules: LineQtyRules
  """Resolved unit price; null when noPriceInCurrency is true."""
  salePrice: Float
  """Per-product tax for the requested quantity (post-discount base) (P1d)."""
  tax: LineTaxInfo
  """
  Full qty-break schedule per selected UOM, ascending by minQuantity (P1d).
  """
  tierBreaks: [LineTierBreak!]
  """Discount % from the effective tier scheme."""
  tierDiscountPercentage: Float
  """Total automatic discount % (tier + global + other)."""
  totalDiscountPercentage: Float
}

"""One volume tier of a variant's price."""
type CustomerVariantSlabPrice {
  "ISO 4217 currency code."
  currencyCode: String
  """The largest quantity the tier applies to. Empty means open-ended."""
  maxQuantity: Float
  """The smallest quantity the tier applies to."""
  minQuantity: Float
  """
  The price before a discount, set only when a discount applied to this tier.
  """
  originalPrice: Float
  """The price in the tier."""
  price: Float!
  "The ID of the unit of measure."
  uomId: String
}

"""
A product the buyer viewed in the app, and whether a committed order of theirs in the same 30 days contains it.
"""
type CustomerViewedProduct {
  """The name of the product. Empty when the product was deleted."""
  name: String
  """True when a committed order of theirs in the same period contains it."""
  ordered: Boolean!
  "The ID of the product."
  productId: ID!
  """How many views."""
  views: Int!
}

"""
Write MANY buying lists in ONE round trip. Covers both axes the app needs: many variants into one list (the add-products sheet) AND one variant across many lists (the add-to-list sheet), adds and removes together.
"""
input CustomerWriteBuyingListsInput {
  """The changes to make, one group per list."""
  lists: [CustomerBuyingListWriteGroup!]!
}

"""A page of customers, for the offline sales rep app."""
type CustomersPage {
  """The customers on this page."""
  items: [Customer!]!
  """
  An opaque cursor to pass back for the next page. Empty on the last page.
  """
  nextCursor: String
}

"""The average days between stages of the sales cycle."""
type CycleTimes {
  """Days from invoice to payment."""
  invoiceToPaid: Float
  """Days from order to invoice."""
  orderToInvoice: Float
  """Days from quote to order."""
  quoteToOrder: Float
  """Days from quote to payment."""
  total: Float!
}

"""Sales for one day."""
type DailySales {
  """The day."""
  date: String!
  """How many orders."""
  orders: Int!
  """The revenue."""
  revenue: Float!
  """How many units were sold."""
  units: Int!
}

"""What the home dashboard shows."""
type DashboardHome {
  """What is waiting for action."""
  actionQueue: ActionQueue!
  """The headline figures."""
  kpis: DashboardKpis!
  """Revenue over the period."""
  revenueTrend: [TrendPoint!]!
  """Whose figures these are."""
  scope: AnalyticsScope!
}

"""
The headline figures of the dashboard, in the organization's base currency.
"""
type DashboardKpis {
  """
  The commission still pending. Empty unless the user has commission rows.
  """
  commissionsPending: Float
  """
  The value of the items on open orders that have not shipped yet, net of short-closed quantities. Includes orders awaiting payment; shipped orders are left out.
  """
  openOrderValue: Float!
  """How many open orders still have items to ship."""
  openOrders: Int!
  """The amount overdue from customers."""
  overdueReceivables: Float!
  """The value of open quotes in the pipeline."""
  pipelineValue: Float!
  """The revenue in the period."""
  revenue: Float!
}

"""Headline figures for the dashboard."""
type DashboardStats {
  """How many are active."""
  activeCustomers: Int!
  """The average order value."""
  averageOrderValue: Float!
  """The share of quotes that became orders, in percent."""
  conversionRate: Float!
  """How much of customers' credit limits is in use, in percent."""
  customerCreditUtilization: Float!
  """How many times stock turned over."""
  inventoryTurnover: Float!
  """How many items are low on stock."""
  lowStockItems: Int!
  """How many orders are pending."""
  pendingOrders: Int!
  """The value of recent orders."""
  recentOrdersValue: Float!
  """How many customers there are."""
  totalCustomers: Int!
  """The value of all stock."""
  totalInventoryValue: Float!
  """How many orders there are."""
  totalOrders: Int!
  """How many products there are."""
  totalProducts: Int!
  """The total revenue."""
  totalRevenue: Float!
}

"""How the database is performing."""
type DatabaseMetrics {
  """The share of reads served from cache, in percent."""
  cacheHitRate: Float!
  """How many connections are open."""
  connectionCount: Int!
  """The average query time, in milliseconds."""
  queryTime: Float!
}

"""A filter on a date."""
input DateFilter {
  """The start of a range."""
  from: DateTime
  """How to compare. Defaults to on or after."""
  operator: FilterOperator = GTE
  """The end of a range."""
  to: DateTime
  """The date to compare with."""
  value: DateTime
}

"""A period of time."""
input DateRangeInput {
  """The last day."""
  endDate: String!
  """The first day."""
  startDate: String!
}

"""
A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format.
"""
scalar DateTime

"""Stock that has not moved for a long time."""
type DeadStockItem {
  """When the stock last moved."""
  lastMovementAt: DateTime
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The quantity on hand."""
  quantity: Float!
  """The value of the stock."""
  value: Float!
  """The SKU of the variant."""
  variantSku: String!
}

"""
A debit note: money a vendor owes back, for example from a purchase return.
"""
type DebitNote {
  """A signed adjustment to the total, such as rounding."""
  adjustments: Float
  """The note amount before tax."""
  amount: Float!
  """The total applied to invoices so far."""
  appliedAmount: Float
  """The date the note was applied."""
  appliedDate: DateTime
  """
  The total in the organization's base currency, frozen when the note was written. Null on older notes.
  """
  baseTotalAmount: Float
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String
  """The debit note number, unique within the organization."""
  debitNoteNumber: String!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The date the note is due."""
  dueDate: DateTime
  "The ID of the user who created the record."
  enteredBy: String!
  """
  The rate frozen when the note was written: 1 unit of the note's currency in the organization's base currency.
  """
  exchangeRate: Float
  "The unique ID of this record."
  id: ID!
  """Notes for staff only."""
  internalNotes: String
  """The date the note was issued."""
  issueDate: DateTime!
  """Notes shown on the note."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The ID of the purchase invoice the note is raised against."""
  originalInvoiceId: String
  "The ID of the partner."
  partnerId: String!
  """The name of the vendor."""
  partnerName: String
  """The credit still available to apply."""
  remainingAmount: Float
  """The ID of the return the note comes from."""
  returnId: String
  """
  Where the note stands: PENDING, APPROVED, PARTIALLY_APPLIED, APPLIED or CANCELLED.
  """
  status: String!
  """The tax on the note."""
  taxAmount: Float!
  """The note total including tax, in the note's currency."""
  totalAmount: Float!
  """What the note is for, for example PURCHASE_RETURN."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""The debit note to raise when a return is processed."""
input DebitNoteDetailsInput {
  """A signed adjustment to the total."""
  adjustments: Float
  """The note amount before tax."""
  amount: Float!
  """Notes shown on the note."""
  notes: String
  """The tax on the note."""
  taxAmount: Float!
}

"""Filters and sorting for the debit note list."""
input DebitNoteFiltersInput {
  "The ID of the partner."
  partnerId: ID
  "Text to search for."
  search: String
  """The column to sort by. Defaults to the debit note number."""
  sortBy: DebitNoteSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only notes in one of these statuses."""
  status: [String!]
  """Only notes of this type."""
  type: String
}

"""The result of a debit note change."""
type DebitNoteResponse {
  """The debit note after the change."""
  debitNote: DebitNote!
  """A message about the outcome."""
  message: String
  """True when the change was made."""
  success: Boolean!
}

"""A column the debit note list can be sorted by."""
enum DebitNoteSortField {
  """When the debit note was created."""
  CREATED_AT
  """The issue date."""
  ISSUE_DATE
  """The total amount."""
  TOTAL_AMOUNT
}

"""
Totals for the debit note list. Counts include every note. Values are in the organization's base currency and cover live notes only.
"""
type DebitNoteSummary {
  """The part of that value already applied."""
  appliedValue: Float!
  """How many are pending."""
  pendingNotes: Int!
  """The part of that value still available to apply."""
  remainingValue: Float!
  """How many debit notes match."""
  totalNotes: Int!
  """The total value of the notes."""
  totalValue: Float!
}

"""A customer or vendor with an open balance."""
type DebtorSlice {
  """The name."""
  name: String!
  """The oldest due date among the open invoices."""
  oldestDueDate: DateTime
  """The amount still owed."""
  outstanding: Float!
  "The ID of the partner."
  partnerId: ID!
}

"""
A customer who was due in the cycle but did not fit within the rep's capacity for it. These are never dropped without a note.
"""
type DeferredVisitCustomer {
  """The key of the customer's tier."""
  customerTier: String
  """
  The tier's current name. Empty when the key matches no tier. Show this rather than the key.
  """
  customerTierName: String
  "The unique ID of this record."
  id: ID!
  """
  When the customer was last visited. Empty means never visited, which counts as most overdue.
  """
  lastVisitedAt: DateTime
  """The name of the customer."""
  name: String!
}

"""Deletes an attribute, or one value of it."""
input DeleteProductAttributeInput {
  """The attribute, in any spelling."""
  attributeKey: String!
  """
  True also removes it from every product carrying it; otherwise a delete of something in use is refused with code PRODUCT_ATTRIBUTE_IN_USE.
  """
  removeFromProducts: Boolean
  """The value to delete; absent deletes the whole attribute."""
  value: String
}

"""
The result of a mutation that deletes a record and has nothing left to return.
"""
type DeleteResponse {
  """A message about the outcome."""
  message: String!
  """True when the record was deleted."""
  success: Boolean!
}

"""
One allow-list decision: whether a partner service may be offered to customers.
"""
type DeliveryAllowedService {
  """True when customers may be offered the service."""
  allowed: Boolean!
  """The ID of the delivery partner that returns the service."""
  deliveryPartnerConfigId: ID!
  """
  `carrier|servicecode`, lower-cased (see DeliverySeenService.serviceKey).
  """
  serviceKey: String!
}

"""Whether customers may be offered one service of a delivery partner."""
input DeliveryAllowedServiceInput {
  """True when customers may be offered the service."""
  allowed: Boolean!
  """The ID of the delivery partner."""
  deliveryPartnerConfigId: ID!
  """The key of the service."""
  serviceKey: String!
}

"""
How AUTO picks the service: CHEAPEST (ties → faster, then partner order), FASTEST (unknown estimate = slowest; ties → cheaper, then partner order), PARTNER_ORDER (the first partner in order that can deliver, at its cheapest service).
"""
enum DeliveryAutoRule {
  """The lowest price. Ties go to the faster service, then partner order."""
  CHEAPEST
  """
  The quickest service; an unknown estimate counts as slowest. Ties go to the cheaper service, then partner order.
  """
  FASTEST
  """The first partner in order that can deliver, at its cheapest service."""
  PARTNER_ORDER
}

"""
How many of one product variant one box holds by the packing engine's rules, what limits it, and a suggested arrangement (which may place fewer: the engine counts volume only).
"""
type DeliveryBoxFitPreview {
  """
  How many the packing engine puts in one such box (counted up to 100,000).
  """
  capacity: Int!
  """
  True when the box holds more than `capacity`: the count stopped at its limit.
  """
  capped: Boolean!
  """
  The variant as packing sees it (size, weight, where each came from), per unit.
  """
  item: PackingItem!
  """The counted units arranged in the box's inside size."""
  layout: PackedBoxLayout!
  """What caps the count."""
  limitedBy: BoxFitLimit!
}

"""
A box being added or edited (inside size and weights, cm / kg) and the product variant to test it with. Nothing is stored.
"""
input DeliveryBoxFitPreviewInput {
  """Inside height, in centimetres."""
  heightCm: Float!
  """Inside length, in centimetres."""
  lengthCm: Float!
  """Most the filled box may weigh (contents + the box), in kilograms."""
  maxWeightKg: Float!
  """The empty box's own weight, in kilograms."""
  tareWeightKg: Float!
  """The product variant to test the box with."""
  variantId: ID!
  """Inside width, in centimetres."""
  widthCm: Float!
}

"""
A standard box size for the Boxes dropdown (common general sizes, not any courier's list; cm / kg).
"""
type DeliveryBoxPreset {
  """The inner height, in centimetres."""
  heightCm: Float!
  """The key of the preset."""
  key: String!
  """The inner length, in centimetres."""
  lengthCm: Float!
  """The most weight the box can hold, in kilograms."""
  maxWeightKg: Float!
  """The name of the box."""
  name: String!
  """The weight of the empty box, in kilograms."""
  tareWeightKg: Float!
  """The inner width, in centimetres."""
  widthCm: Float!
}

"""
How customers choose delivery: LIST (every allowed service), SPEEDS (named speeds, each its best price), AUTO (one price the store picks).
"""
enum DeliveryChoiceMode {
  """One price that the store picks."""
  AUTO
  """Every allowed service."""
  LIST
  """Named speeds, each at its best price."""
  SPEEDS
}

"""
What customers see for delivery: how they choose, which details show, tracking, and which partner services may be offered. Staff screens always see everything.
"""
type DeliveryCustomerDisplay {
  """The services customers may or may not be offered."""
  allowedServices: [DeliveryAllowedService!]!
  """The customer surfaces the shaping applies to."""
  applyTo: CustomerDeliveryApplyTo!
  """The rule that picks the option in AUTO mode."""
  autoRule: DeliveryAutoRule!
  """How customers choose delivery: LIST, SPEEDS or AUTO."""
  choiceMode: DeliveryChoiceMode!
  """
  What happens to a service a partner starts returning: OFFER it or HOLD it until staff decide.
  """
  newServicePolicy: DeliveryNewServicePolicy!
  """What the sales app shows about delivery."""
  salesApp: SalesAppDeliveryView!
  """Which delivery details customer screens show."""
  show: CustomerDeliveryDetails!
  """The delivery speeds customers can pick in SPEEDS mode."""
  speeds: [DeliverySpeed!]!
  """How much tracking detail customers see."""
  tracking: CustomerTrackingLevel!
}

"""
Live prices for one address, shaped exactly as each surface would get them under the given settings. Read-only: no option id redeems, nothing is recorded.
"""
type DeliveryCustomerDisplayPreview {
  """The delivery options the buyer app would show."""
  buyerApp: CheckoutDeliveryOptions!
  """The delivery options the customer portal would show."""
  portal: CheckoutDeliveryOptions!
  """
  The sales app's draft options (customer view only when salesApp is CUSTOMER).
  """
  salesApp: CheckoutDeliveryOptions!
  """The effective settings the preview used."""
  settings: DeliveryCustomerDisplay!
  """Every rated service, nothing hidden (the staff view)."""
  staff: CheckoutDeliveryOptions!
}

"""
What to preview: the delivery options a customer would see at an address.
"""
input DeliveryCustomerDisplayPreviewInput {
  """The customer address to price delivery to."""
  addressId: ID!
  """The customer the address belongs to (narrows the address lookup)."""
  customerId: ID
  """Unsaved settings to preview; omitted fields use the saved ones."""
  settings: UpdateDeliveryCustomerDisplayInput
}

"""
Whether a delivery partner's credentials are for the provider's test or live service.
"""
enum DeliveryEnvironment {
  """The courier's real network."""
  LIVE
  """The courier's test network."""
  SANDBOX
}

"""
How the delivery fee is worked out: a FLAT fee or a LIVE_QUOTE from the delivery partners.
"""
enum DeliveryFeeMode {
  """A fixed delivery fee."""
  FLAT
  """The fee quoted by the courier for each order."""
  LIVE_QUOTE
}

"""
OFFER: a new partner service is offered at once. HOLD: it is held until an admin allows it.
"""
enum DeliveryNewServicePolicy {
  """A new partner service is held until an admin allows it."""
  HOLD
  """A new partner service is offered at once."""
  OFFER
}

"""
SERVICE: one partner service. SPEED: a named speed at its best service. AUTO: the one price the store picked.
"""
enum DeliveryOptionKind {
  """The one price the store picked."""
  AUTO
  """One partner service."""
  SERVICE
  """A named speed at its best service."""
  SPEED
}

"""
A box orders are packed into (inside dimensions, cm / kg; optional outside dimensions and cost).
"""
type DeliveryPackingBox {
  """
  What one empty box costs the seller — a decimal string in the organization's base currency; null = not set. Staff only; never part of the customer's delivery fee.
  """
  costPerBox: String
  """
  The Default box's weight when its contents are unknown (kg); null = no fallback parcel. Always null on other boxes.
  """
  defaultWeightKg: Float
  """True when the box is used for packing."""
  enabled: Boolean!
  """Inside height."""
  heightCm: Float!
  """Stable id (kept across edits)."""
  id: String!
  """
  The Default box (at most one): sent to couriers when an order cannot be packed and when staff book without a parcel, whether or not it is enabled.
  """
  isDefault: Boolean!
  """Inside length (what fits)."""
  lengthCm: Float!
  """Most the filled box may weigh (contents + the box itself)."""
  maxWeightKg: Float!
  """The name of the box."""
  name: String!
  """Outside height (≥ inside); null = the inside height."""
  outerHeightCm: Float
  """
  Outside length (≥ inside) — sent to couriers and used for size weight; null = the inside length.
  """
  outerLengthCm: Float
  """Outside width (≥ inside); null = the inside width."""
  outerWidthCm: Float
  """Only these delivery partner configs may use it; null = every partner."""
  partnerConfigIds: [ID!]
  """The standard size it started from, or null for a custom box."""
  presetKey: String
  """The empty box's own weight."""
  tareWeightKg: Float!
  """Inside width."""
  widthCm: Float!
}

"""A box type used for packing."""
input DeliveryPackingBoxInput {
  """
  What one empty box costs (decimal string ≥ 0, organization base currency); null = no cost.
  """
  costPerBox: String
  """
  The Default box's weight when its contents are unknown (kg, at most maxWeightKg); null = no fallback parcel. Ignored on other boxes.
  """
  defaultWeightKg: Float
  """True when the box is used for packing."""
  enabled: Boolean
  """The inner height, in centimetres."""
  heightCm: Float!
  """The box's id; omit for a new box."""
  id: String
  """
  Make this the Default box (at most one): sent to couriers when an order cannot be packed and when staff book without a parcel.
  """
  isDefault: Boolean
  """The inner length, in centimetres."""
  lengthCm: Float!
  """The most weight the box can hold, in kilograms."""
  maxWeightKg: Float!
  """The name of the box."""
  name: String!
  """Outside height (≥ the inside height); null = the inside height."""
  outerHeightCm: Float
  """Outside length (≥ the inside length); null = the inside length."""
  outerLengthCm: Float
  """Outside width (≥ the inside width); null = the inside width."""
  outerWidthCm: Float
  """The delivery partners that accept the box. Empty means all."""
  partnerConfigIds: [ID!]
  """The key of the box preset it was made from."""
  presetKey: String
  """The weight of the empty box, in kilograms."""
  tareWeightKg: Float
  """The inner width, in centimetres."""
  widthCm: Float!
}

"""Item size and weight used when a variant and its categories have none."""
type DeliveryPackingItemDefaults {
  """The height, in centimetres."""
  heightCm: Float
  """The length, in centimetres."""
  lengthCm: Float
  """The weight, in kilograms."""
  weightKg: Float
  """The width, in centimetres."""
  widthCm: Float
}

"""The size and weight to assume for an item that has none of its own."""
input DeliveryPackingItemDefaultsInput {
  """The height, in centimetres."""
  heightCm: Float
  """The length, in centimetres."""
  lengthCm: Float
  """The weight, in kilograms."""
  weightKg: Float
  """The width, in centimetres."""
  widthCm: Float
}

"""
Settings → Shipment → Boxes. With no enabled box, delivery quotes use the single default parcel exactly as before.
"""
type DeliveryPackingSettings {
  """The box types available for packing."""
  boxes: [DeliveryPackingBox!]!
  """The size and weight assumed for an item that has none of its own."""
  defaultItem: DeliveryPackingItemDefaults!
  """How full a box can really be packed (%)."""
  fillPercent: Float!
  """
  How full a box of fragile items can be packed (%). Fragile items never share a box with others.
  """
  fragileFillPercent: Float!
  """
  Orders packed heavier than this (kg) are not live-quoted; staff quote the delivery. Null = off.
  """
  freightQuoteAboveKg: Float
  """Most boxes that can be saved."""
  maxBoxes: Int!
  """
  Orders that pack into more boxes than this are not live-quoted; staff quote the delivery. Null = off.
  """
  maxBoxesPerOrder: Int
  """True when customers see how many boxes their order packs into."""
  showBoxCountToCustomers: Boolean!
  """
  The measurement system the console shows and accepts. Stored sizes are always centimetres and kilograms.
  """
  units: PackingMeasurementSystem!
  """
  True when units were never saved: the value shown is the default for the organization's country.
  """
  unitsIsDefault: Boolean!
  """cm³ per kg used to compare packings (size weight = L×W×H ÷ divisor)."""
  volumetricDivisor: Int!
}

"""The size and weight of one parcel."""
type DeliveryParcelGql {
  """The height, in centimetres."""
  heightCm: Float!
  """The length, in centimetres."""
  lengthCm: Float!
  """The weight, in kilograms."""
  weightKg: Float!
  """The width, in centimetres."""
  widthCm: Float!
}

"""One parcel's dimensions and weight."""
input DeliveryParcelInput {
  """Parcel height in centimetres. Must be greater than zero."""
  heightCm: Float!
  """Parcel length in centimetres. Must be greater than zero."""
  lengthCm: Float!
  """Parcel weight in kilograms. Must be greater than zero."""
  weightKg: Float!
  """Parcel width in centimetres. Must be greater than zero."""
  widthCm: Float!
}

"""
A delivery partner the organization has set up. Secret credentials are never returned.
"""
type DeliveryPartnerConfigGql {
  """
  False when the provider's adapter is no longer installed. The partner is then read-only.
  """
  available: Boolean!
  """
  The secret credential fields that have a stored value. The values themselves are never returned.
  """
  configuredSecretKeys: [String!]!
  """The name to show for the partner."""
  displayName: String!
  """The provider environment the credentials belong to."""
  environment: DeliveryEnvironment!
  "The unique ID of this record."
  id: ID!
  """True when the partner is offered at checkout and to staff."""
  isEnabled: Boolean!
  """
  The partner's own uploaded logo, else the provider's built-in logo, else empty.
  """
  logoUrl: String
  """The non-secret credential fields with their values."""
  nonSecretValues: [DeliveryPartnerKeyValue!]!
  """The provider key."""
  providerKey: String!
  """The partner's settings with their values."""
  settingsValues: [DeliveryPartnerKeyValue!]!
  """The short name of the partner, used in URLs."""
  slug: String!
  """The position of the partner in lists, lowest first."""
  sortOrder: Int!
  "When the record was last changed."
  updatedAt: DateTime!
  """
  Legacy, ignored: every enabled partner is offered at checkout (2026-10-13).
  """
  useForCheckout: Boolean!
  """The result of the last verification."""
  verification: DeliveryPartnerVerification!
  """
  The webhook URL to paste into the provider's dashboard. Empty when the provider has no webhooks.
  """
  webhookUrl: String
}

"""One credential a delivery provider needs, such as an API key."""
type DeliveryPartnerCredentialField {
  """Guidance on where to find the value."""
  helpText: String
  """The name of the credential field."""
  key: String!
  """The label to show for the field."""
  label: String!
  """An example value to show in the empty field."""
  placeholder: String
  """True when the value is a secret and is never returned once saved."""
  secret: Boolean!
}

"""One choice of a select setting."""
type DeliveryPartnerFieldOption {
  """The text to show."""
  label: String!
  """The value that is saved."""
  value: String!
}

"""
Shows a setting only while another setting has one of the given values.
"""
type DeliveryPartnerFieldVisibility {
  """The key of the controlling setting."""
  key: String!
  """
  The values of that setting that show the field. An empty string means unset.
  """
  values: [String!]!
}

"""A setting or credential name and its value."""
type DeliveryPartnerKeyValue {
  """The name."""
  key: String!
  """The value."""
  value: String!
}

"""A setting or credential name and the value to store."""
input DeliveryPartnerKeyValueInput {
  """The name."""
  key: String!
  """The value."""
  value: String!
}

"""
What a delivery provider declares about itself: the credentials and settings it needs, and what it supports. The admin page is built from this.
"""
type DeliveryPartnerProviderInfo {
  """What the provider supports, such as RATES, BOOKING or RETURNS."""
  capabilities: [String!]!
  """The credentials to collect."""
  credentialFields: [DeliveryPartnerCredentialField!]!
  """What the provider is."""
  description: String!
  """The provider's name."""
  displayName: String!
  """The provider key."""
  key: String!
  """
  API when the system books with the provider, MANUAL for a custom courier whose status staff record by hand.
  """
  kind: String!
  """The provider's built-in logo, or empty to show a monogram."""
  logoUrl: String
  """
  True when the provider can be set up more than once, as custom couriers can.
  """
  multipleAllowed: Boolean!
  """The settings to collect."""
  settingsFields: [DeliveryPartnerSettingsField!]!
  """The countries the provider serves."""
  supportedCountries: [String!]
  """The currencies the provider quotes in."""
  supportedCurrencies: [String!]
  """
  How the provider's webhooks are authenticated: HMAC, URL_TOKEN or NONE.
  """
  webhookAuth: String!
}

"""One setting a delivery provider offers."""
type DeliveryPartnerSettingsField {
  """Guidance on what the setting does."""
  helpText: String
  """The name of the setting."""
  key: String!
  """The label to show for the setting."""
  label: String!
  """The choices of a select setting."""
  options: [DeliveryPartnerFieldOption!]
  """An example value to show in the empty field."""
  placeholder: String
  """True when the setting must be filled in."""
  required: Boolean
  """
  The kind of input: text, number, boolean, select, url-template, money, image or rate-card.
  """
  type: String!
  """The condition that shows the setting. Always shown when empty."""
  visibleWhen: DeliveryPartnerFieldVisibility
}

"""The result of checking a delivery partner's credentials and webhook."""
type DeliveryPartnerVerification {
  """Detail from the credential check, such as why it failed."""
  keysCheckDetail: String
  """When the credentials were last checked."""
  keysCheckedAt: String
  """True when the saved credentials were accepted by the provider."""
  keysValid: Boolean!
  """
  True when a credential edit disabled the partner. Verify it again, then enable it.
  """
  needsReverification: Boolean!
  """True when the provider's webhook reached the API."""
  webhookReachable: Boolean!
  """When the webhook was registered with the provider."""
  webhookRegisteredAt: String
}

"""
A service a partner has returned for this tenant (the allow-list table's rows).
"""
type DeliverySeenService {
  """The courier that offers the service."""
  carrierName: String!
  """ISO-4217 currency of `lastAmount`."""
  currency: String!
  """
  False when no admin has decided it yet (it follows the new-service policy) — show it as New.
  """
  decided: Boolean!
  """When the service was first returned."""
  firstSeenAt: DateTime!
  """The last carrier price seen, in `currency` (an example price)."""
  lastAmount: Float!
  """When the service was last returned."""
  lastSeenAt: DateTime!
  """Offered to customers under the saved settings."""
  offered: Boolean!
  """The allow-list key: `carrier|servicecode`, lower-cased."""
  serviceKey: String!
  """The code of the service level."""
  serviceLevelCode: String!
  """The name of the service level."""
  serviceLevelName: String!
}

"""The services one delivery partner has returned."""
type DeliverySeenServiceGroup {
  """The ID of the delivery partner."""
  deliveryPartnerConfigId: ID!
  """True when the partner is enabled."""
  isEnabled: Boolean!
  """The name of the delivery partner."""
  partnerDisplayName: String!
  """The services the partner has returned."""
  services: [DeliverySeenService!]!
}

"""The organization's delivery settings."""
type DeliverySettingsGql {
  """
  Deprecated and not read: a carrier's delivered report always marks the order delivered.
  """
  autoDeliverFromCarrier: Boolean! @deprecated(reason: "Always on: a carrier's delivered marks the order delivered (D-127). Not read.")
  """
  False until the settings are saved. Until then the older flat-fee sources still apply.
  """
  configured: Boolean!
  """True to email the customer when an outbound shipment is delivered."""
  customerEmailOnDelivered: Boolean!
  """True to email the customer when an outbound shipment is booked."""
  customerEmailOnShipped: Boolean!
  """
  Deprecated: the parcel size and weight to quote with when none is given. The Default box replaces it.
  """
  defaultParcel: DeliveryParcelGql @deprecated(reason: "The fallback parcel is the Default box (deliveryPackingSettings.boxes[].isDefault). Read only until the boxes are saved again.")
  """
  Deprecated and not read: the warehouse shipments were collected from by default.
  """
  defaultPickupWarehouseId: String @deprecated(reason: "Not read: couriers collect from the order line's warehouse, else the Inventory default warehouse.")
  """
  How the delivery fee is worked out: a flat fee or a live quote from the delivery partners.
  """
  feeMode: DeliveryFeeMode!
  """
  The flat delivery fee, as a decimal string in the organization's base currency.
  """
  flatFee: String
  """
  The order total at or above which delivery is free, as a decimal string. Empty means no threshold.
  """
  freeDeliveryThreshold: String
  """
  The order total at or above which live-quoted delivery is free, as a decimal string. Empty means no threshold.
  """
  liveQuoteFreeThreshold: String
  """
  The default layout of the shipping sticker. Leave out to keep the saved one.
  """
  stickerFormat: ShipmentStickerFormat!
  """
  The height of the custom sticker size, in whole millimetres. Null clears it. Leave out to keep the saved one.
  """
  stickerHeightMm: Int
  """
  The width of the custom sticker size, in whole millimetres. Null clears it. Leave out to keep the saved one.
  """
  stickerWidthMm: Int
}

"""A delivery speed customers can pick in SPEEDS mode."""
type DeliverySpeed {
  """True when customers can pick the speed."""
  enabled: Boolean!
  """Stable id (kept across renames)."""
  id: String!
  """
  Services estimated to arrive within this many days qualify; null = any time (incl. no estimate).
  """
  maxDays: Int
  """The name customers see."""
  name: String!
}

"""A delivery speed customers can pick."""
input DeliverySpeedInput {
  """True when customers can pick the speed."""
  enabled: Boolean!
  """
  Keep the id of an existing speed; omit for a new one (the server mints it).
  """
  id: String
  """Days; null = any time (incl. no estimate)."""
  maxDays: Int
  """The name customers see."""
  name: String!
}

"""A device the user has signed in from."""
type DeviceInfo {
  """The browser."""
  browser: String
  """The name of the device."""
  deviceName: String!
  """The kind of device."""
  deviceType: String!
  "The unique ID of this record."
  id: ID!
  """True when this is the device in use now."""
  isCurrent: Boolean!
  """When the device was last used."""
  lastUsedAt: DateTime!
  """The operating system."""
  os: String
  """When the device stops being trusted for two-factor."""
  trustedUntil: DateTime!
}

"""When discount is applied"""
enum DiscountApplication {
  """Applied when the customer checks out."""
  AT_CHECKOUT
  """Applied to the price straight away."""
  IMMEDIATE
  """Applied on the invoice."""
  INVOICE
  """Applied when the payment is made."""
  PAYMENT
}

"""Type of discount calculation"""
enum DiscountCalculationType {
  """A fixed amount off."""
  FIXED_AMOUNT
  """A percentage off."""
  PERCENTAGE
}

"""One discount that was considered."""
type DiscountDetail {
  """The code of the scheme."""
  code: String!
  """The discount on this amount."""
  discountAmount: Float!
  """The fixed discount amount."""
  fixedAmount: Float
  "The unique ID of this record."
  id: String!
  """True when the discount was applied."""
  isApplied: Boolean!
  """The name of the scheme."""
  name: String!
  """The discount in percent."""
  percentage: Float
  """
  Where the discount came from: TIER, CUSTOMER, GLOBAL, PRODUCT or CATEGORY.
  """
  source: String
  """How the discount is worked out."""
  type: String!
}

"""A discount scheme."""
type DiscountScheme {
  """The customer types the scheme applies to."""
  applicableCustomerTypes: String
  """The regions the scheme applies to."""
  applicableRegions: String
  """Where the discount is applied."""
  application: DiscountApplication!
  """For a buy-and-get scheme, how many to buy."""
  buyQuantity: Float
  """The code of the scheme."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  """
  The ID of the currency the scheme is for. Empty means the base currency.
  """
  currencyId: String
  """How many times it has been used."""
  currentUsage: Int!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the scheme is for."""
  description: String
  "The ID of the user who created the record."
  enteredBy: String!
  """The fixed discount amount."""
  fixedAmountValue: Float
  """For a buy-and-get scheme, how many come free."""
  getQuantity: Float
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """True when the scheme can combine with other discounts."""
  isStackable: Boolean!
  """
  True when customers are put on the scheme automatically through customer tier settings.
  """
  isTierManaged: Boolean!
  """The most discount the scheme may give."""
  maxDiscountAmount: Float
  """The most times one customer may use the scheme."""
  maxUsagePerCustomer: Int
  """The most times the scheme may be used in all."""
  maxUsageTotal: Int
  """The smallest order amount the scheme applies to."""
  minOrderAmount: Float
  """The name of the scheme."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The customers on the scheme."""
  partners: [DiscountSchemePartner!]
  """The discount in percent."""
  percentageValue: Float
  """Which scheme wins when several apply. Higher goes first."""
  priority: Int!
  """The products on the scheme."""
  products: [DiscountSchemeProduct!]
  """What the scheme applies to."""
  scope: DiscountScope!
  """How the discount is worked out."""
  type: DiscountType!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """When the scheme starts."""
  validFrom: DateTime!
  """When the scheme ends."""
  validTo: DateTime
}

"""Filters and sorting for the discount scheme list."""
input DiscountSchemeFilterInput {
  """Only schemes for this currency."""
  currencyId: String
  "Whether the record is active."
  isActive: Boolean
  """Only schemes with this scope."""
  scope: DiscountScope
  "Text to search for."
  search: String
  """The column to sort by. Defaults to newest first."""
  sortBy: DiscountSchemeSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only schemes in this status."""
  status: DiscountSchemeStatusFilter
}

"""A customer on a discount scheme."""
type DiscountSchemePartner {
  "When the record was created."
  createdAt: DateTime!
  """The ID of the scheme."""
  discountSchemeId: String!
  "The unique ID of this record."
  id: ID!
  """The customer."""
  partner: Partner!
  "The ID of the partner."
  partnerId: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A product on a discount scheme."""
type DiscountSchemeProduct {
  "When the record was created."
  createdAt: DateTime!
  """The ID of the scheme."""
  discountSchemeId: String!
  "The unique ID of this record."
  id: ID!
  """The product."""
  product: Product!
  "The ID of the product."
  productId: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the product variant."
  variantId: String
}

"""A column the discount scheme list can be sorted by."""
enum DiscountSchemeSortField {
  """When the scheme was created."""
  CREATED_AT
  """The scheme name."""
  NAME
  """The scheme priority."""
  PRIORITY
  """The date the scheme starts."""
  VALID_FROM
}

"""
The status of a discount scheme: ACTIVE, INACTIVE, EXPIRED or SCHEDULED.
"""
enum DiscountSchemeStatusFilter {
  """Schemes in effect now."""
  ACTIVE
  """Schemes whose end date has passed."""
  EXPIRED
  """Schemes that are switched off."""
  INACTIVE
  """Schemes that start in the future."""
  SCHEDULED
}

"""Headline discount scheme counts."""
type DiscountSchemesSummary {
  """How many are active."""
  activeSchemes: Int!
  """How many have ended."""
  expiredSchemes: Int!
  """How many start in the future."""
  scheduledSchemes: Int!
  """How many schemes there are."""
  totalSchemes: Int!
}

"""Scope of discount application"""
enum DiscountScope {
  """Products in a category."""
  CATEGORY
  """One customer."""
  CUSTOMER
  """Every order."""
  GLOBAL
  """The whole order."""
  ORDER
  """One product."""
  PRODUCT
}

"""Type of discount"""
enum DiscountType {
  """Buy a number of items and get others free or cheaper."""
  BUY_X_GET_Y
  """A discount on a category."""
  CATEGORY
  """A discount for a customer tier."""
  CUSTOMER_TIER
  """A fixed amount off."""
  FIXED_AMOUNT
  """A loyalty reward."""
  LOYALTY
  """A discount based on the order total."""
  ORDER_TOTAL
  """A percentage off."""
  PERCENTAGE
  """A discount on a product."""
  PRODUCT
  """A discount on shipping."""
  SHIPPING
  """A discount that grows with the quantity bought."""
  VOLUME_TIER
}

"""How a discount scheme has been used."""
type DiscountUsageStats {
  """The average discount per order."""
  averageDiscountPerOrder: Float!
  """The total discount given."""
  totalDiscountAmount: Float!
  """How many times it was used."""
  totalUsage: Int!
  """How many different customers used it."""
  uniqueCustomers: Int!
}

"""
The organization's brand identity as it is resolved, one value each, applied to every PDF and document email.
"""
type DocumentBrandConfig {
  """Accent color hex, e.g. #4F46E5"""
  accentColor: String
  """The company address printed on documents."""
  companyAddress: String
  """The company name printed on documents."""
  companyName: String
  """The footer text printed on documents."""
  footerText: String
  """Inline base64 data URL of the logo"""
  logoAssetKey: String
}

"""A document's approval requests and its standing control refusal."""
type DocumentControlStatus {
  """
  The newest enforced block, while nothing else has happened on the document since.
  """
  lastRefusal: ControlRefusalSummary
  """The latest five requests, newest first."""
  requests: [ControlApprovalRequest!]!
}

"""
The organization's own wording for one type of outbound document email: the subject line and one body paragraph, merged over the default template.
"""
type DocumentEmailCopy {
  """One body paragraph ({{token}} placeholders). Null = registry default"""
  body: String
  """Registry key, e.g. 'QUOTE' | 'INVOICE' | 'PAYMENT_RECEIPT'"""
  emailType: String!
  "The unique ID of this record."
  id: ID!
  """Subject override ({{token}} placeholders). Null = registry default"""
  subject: String
  "When the record was last changed."
  updatedAt: DateTime!
}

"""
An edit in progress, laid over the saved brand and wording so the editor can preview an email before saving.
"""
input DocumentEmailDraftInput {
  """The draft accent colour."""
  accentColor: String
  """The draft body paragraph."""
  body: String
  """The draft subject line."""
  subject: String
}

"""A rendered sample of one outbound document email."""
type DocumentEmailPreview {
  """Fully rendered email body HTML"""
  html: String!
  """Resolved content locale: 'en' | 'es' | 'fr' | 'ms'"""
  locale: String!
  """The subject line."""
  subject: String!
  """The version of the template used."""
  templateVersion: Int!
  """Registry key, e.g. 'QUOTE' | 'INVOICE' | 'PAYMENT_RECEIPT'"""
  type: String!
}

"""One previewable email template."""
type DocumentEmailTemplateInfo {
  """{{token}} names the body override may use."""
  bodyTokens: [String!]!
  """
  {{token}} names the subject override may use. Empty for types whose wording is not editable (THREAD_REPLY).
  """
  subjectTokens: [String!]!
  """The version of the template."""
  templateVersion: Int!
  """The kind of document email."""
  type: String!
}

"""The number series of one document type, as Settings shows it."""
type DocumentNumberSeries {
  """NONE | YYYY | FY | YYMM | YYYYMM | YYYYMMDD"""
  dateFormat: String!
  """The kind of document."""
  docType: DocumentNumberType!
  """Differs from the built-in default"""
  isCustomized: Boolean!
  """The highest number already issued in the current period"""
  lastIssued: String
  """
  The sequence the next document will get — never at or below one already issued
  """
  nextNumber: Int!
  """Minimum digits in the sequence"""
  padWidth: Int!
  """The prefix of the numbers."""
  prefix: String!
  """The number the next document will get"""
  preview: String!
  """NEVER | YEARLY | MONTHLY | DAILY"""
  resetPolicy: String!
  """'' | '-' | '/' | '_'"""
  separator: String!
}

"""A document type that mints its own number series"""
enum DocumentNumberType {
  """Receipts for money collected."""
  COLLECTION
  """Credit notes."""
  CREDIT_NOTE
  """Debit notes."""
  DEBIT_NOTE
  """Returns of defective goods."""
  DEFECTIVE_RETURN
  """Returns for exchange."""
  EXCHANGE_RETURN
  """Goods receipt notes."""
  GRN
  """Internal returns."""
  INTERNAL_RETURN
  """Payments made."""
  PAYMENT
  """Purchase invoices."""
  PURCHASE_INVOICE
  """Purchase orders."""
  PURCHASE_ORDER
  """Returns to suppliers."""
  PURCHASE_RETURN
  """Quotes."""
  QUOTE
  """Sales invoices."""
  SALES_INVOICE
  """Sales orders."""
  SALES_ORDER
  """Returns from customers."""
  SALES_RETURN
  """Service returns."""
  SERVICE_RETURN
  """Shipments."""
  SHIPMENT
  """Stock adjustments."""
  STOCK_ADJUSTMENT
  """Stock cycle counts."""
  STOCK_CYCLE_COUNT
  """Stock issues."""
  STOCK_ISSUE
  """Stock receipts."""
  STOCK_RECEIPT
  """Stock returns."""
  STOCK_RETURN
  """Stock transfers."""
  STOCK_TRANSFER
  """Warranty returns."""
  WARRANTY_RETURN
}

"""The number series of every document type."""
type DocumentNumberingSettings {
  """Fiscal-year start (MM-DD) that YEARLY resets and FY follow"""
  fiscalYearStart: String!
  """Today in the organization's timezone (YYYY-MM-DD)"""
  localDate: String!
  """The series."""
  series: [DocumentNumberSeries!]!
}

"""The owner of a document."""
type DocumentOwnerOutput {
  """The email address of the owner."""
  userEmail: String
  "The ID of the user."
  userId: String!
  """The name of the owner."""
  userName: String!
}

"""Who owns a document: a single owner."""
input DocumentOwnershipInput {
  """The ID of the user who owns the document."""
  ownerId: String
}

"""Who owns a document."""
type DocumentOwnershipOutput {
  """The owner."""
  owner: DocumentOwnerOutput
}

"""Document settings."""
input DocumentSettingsInput {
  """True to archive documents."""
  archiveDocuments: Boolean
  """How long documents are kept."""
  archiveDuration: String
  """The date format on documents."""
  dateFormat: String
  """The default paper size."""
  defaultPaperSize: String
  """True to add a digital signature."""
  enableDigitalSignature: Boolean
  """True to print a watermark."""
  enableWatermark: Boolean
  """The footer text."""
  footerText: String
  """True to print the company logo."""
  includeCompanyLogo: Boolean
  """Where the logo goes."""
  logoPosition: String
  """The number format on documents."""
  numberFormat: String
  """The watermark text."""
  watermarkText: String
}

"""The organization's setup of one document template."""
type DocumentTemplateConfig {
  """Accent color hex, e.g. #4F46E5"""
  accentColor: String
  """The company address printed on the document."""
  companyAddress: String
  """The company name printed on the document."""
  companyName: String
  """
  'quote' | 'invoice' | 'purchase_order' (covers sales + purchase orders) | 'credit_note' | 'debit_note' | 'payment'
  """
  documentType: String!
  """The footer text printed on the document."""
  footerText: String
  "The unique ID of this record."
  id: ID!
  """MinIO object key of the uploaded logo"""
  logoAssetKey: String
  """'professional' | 'modern' | 'classic'"""
  style: String!
  """The terms printed on the document."""
  terms: String
  "When the record was last changed."
  updatedAt: DateTime!
  """Visible column keys"""
  visibleColumns: [String!]
}

"""
The editable parts of a document template. Every field is optional so the same type can carry a partial draft for a live preview.
"""
input DocumentTemplateDraftInput {
  """The accent colour."""
  accentColor: String
  """The company address printed on the document."""
  companyAddress: String
  """The company name printed on the document."""
  companyName: String
  """The footer text printed on the document."""
  footerText: String
  """Inline base64 data URL (data:image/...), or "" to clear"""
  logoAssetKey: String
  """The layout style of the document."""
  style: String
  """The terms printed on the document."""
  terms: String
  """The columns shown in the line items table."""
  visibleColumns: [String!]
}

"""
A customer's tier for display: the tier that would be charged, worked out from the current month's spend.
"""
type EffectiveTierInfo {
  """
  How the tier's discount is worked out. Empty when the tier has no scheme.
  """
  discountType: DiscountType
  """The tier's fixed discount amount."""
  fixedAmountValue: Float
  "Whether this is the default."
  isDefault: Boolean!
  """
  True when the tier is pinned by hand and automatic tiering will not move it.
  """
  locked: Boolean!
  """The customer's order value this month."""
  monthlySpend: Float!
  """The name of the next tier up."""
  nextTierName: String
  """The spend at which the next tier starts."""
  nextTierThreshold: Float
  """The tier's discount in percent."""
  percentageValue: Float
  """
  How much more the customer must spend this month to reach the next tier.
  """
  remainingToNextTier: Float
  """The key of the tier."""
  tierKey: String!
  """The name of the tier."""
  tierName: String!
  """The spend at which the tier starts."""
  tierThreshold: Float!
}

"""The organization's email settings. Secrets are never returned."""
type EmailConfig {
  "When the record was created."
  createdAt: DateTime!
  """The ID of the user who created the settings."""
  createdBy: String!
  """The time of day the daily report is sent."""
  dailyReportTime: String
  """The addresses reports and alerts go to by default."""
  defaultRecipients: [String!]
  """The signature added to mail."""
  emailSignature: String
  """The address mail is sent from."""
  fromEmail: String!
  """The name mail is sent from."""
  fromName: String!
  """True when an API key is stored."""
  hasApiKey: Boolean
  """True when an SMTP password is stored."""
  hasSmtpPassword: Boolean
  "The unique ID of this record."
  id: String!
  """True when sending is switched on."""
  isEnabled: Boolean!
  """The day of the month the monthly report is sent."""
  monthlyReportDate: Int
  "The ID of the organization the record belongs to."
  organizationId: String!
  """
  The email provider: SMTP, SENDGRID, AWS_SES, MAILGUN, RESEND or GOOGLE.
  """
  provider: EmailProvider!
  """The address replies go to."""
  replyToEmail: String
  """True to send alert emails."""
  sendAlerts: Boolean!
  """True to send notification emails."""
  sendNotifications: Boolean!
  """True to send report emails."""
  sendReports: Boolean!
  """The SMTP server."""
  smtpHost: String
  """The SMTP port."""
  smtpPort: Int
  """True to use a secure connection."""
  smtpSecure: Boolean
  """The SMTP user name."""
  smtpUser: String
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The day of the week the weekly report is sent."""
  weeklyReportDay: Int
}

"""A saved email draft."""
type EmailDraft {
  """The draft body as HTML."""
  bodyHtml: String!
  """Addresses copied."""
  ccEmails: [String!]!
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """The ID of the email this draft replies to."""
  inReplyToId: String
  """The ID of the document the draft relates to."""
  referenceId: String
  """Type of document the draft relates to."""
  referenceType: String
  """Subject line."""
  subject: String!
  """Recipient addresses."""
  toEmails: [String!]!
  """Kind of draft (for example a new email, a reply or a forward)."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""
The service that sends the organization's email: SMTP, SENDGRID, AWS_SES, MAILGUN, RESEND or GOOGLE.
"""
enum EmailProvider {
  """Amazon SES."""
  AWS_SES
  """Google Workspace."""
  GOOGLE
  """Mailgun."""
  MAILGUN
  """Resend."""
  RESEND
  """SendGrid."""
  SENDGRID
  """A custom SMTP server."""
  SMTP
}

"""Type of document the email relates to"""
enum EmailReferenceType {
  """An email that is not tied to a document."""
  GENERAL
  """An email about a quote."""
  QUOTE
  """An email about a sales order."""
  SALES_ORDER
}

"""A DNS record to add so the organization's own domain can send mail."""
type EmailSenderDnsRecord {
  """The name of the record."""
  host: String!
  """
  DKIM, which signs the mail, or RETURN_PATH, which aligns SPF for DMARC.
  """
  purpose: String!
  """TXT or CNAME."""
  type: String!
  """The value of the record."""
  value: String!
  """True when the record was found."""
  verified: Boolean!
}

"""A domain the organization sends mail from."""
type EmailSenderDomain {
  """The DNS records to add."""
  dnsRecords: [EmailSenderDnsRecord!]!
  """The domain."""
  domain: String!
  "The unique ID of this record."
  id: String!
  """When the records were last checked."""
  lastCheckedAt: DateTime
  """Why the last check failed."""
  lastError: String
  """Where verification stands."""
  status: EmailSenderDomainStatus!
  """When the domain was verified."""
  verifiedAt: DateTime
}

"""
Where verification of a sending domain stands: PENDING, VERIFIED or FAILED.
"""
enum EmailSenderDomainStatus {
  """Verification failed."""
  FAILED
  """Waiting for the DNS records to be checked."""
  PENDING
  """Verified and ready to send from."""
  VERIFIED
}

"""
What the email settings page needs to say truthfully about which address document mail goes out from. It is worked out by the same resolver the send path uses.
"""
type EmailSenderSetup {
  """The organization's sending domain, if it set one up."""
  domain: EmailSenderDomain
  """
  The domain of the platform's document sender, for the case where mail goes out from it.
  """
  platformDomain: String!
  """
  False on a deploy with no provider account, which the domain card explains.
  """
  providerAvailable: Boolean!
  """The Reply-To used for invoices, receipts, notes and reminders."""
  replyTo: String
  """
  The organization's own From address when document mail will use it. Empty means the platform address.
  """
  sendingFrom: String
  """
  Why: TENANT_DOMAIN, NO_FROM_ADDRESS, NO_VERIFIED_DOMAIN or ADDRESS_NOT_ON_DOMAIN.
  """
  sendingFromReason: String!
}

"""Email settings."""
input EmailSettingsInput {
  """The addresses blind-copied on every outbound document email."""
  documentEmailBcc: [String!]
  """The addresses copied on every outbound document email."""
  documentEmailCc: [String!]
  """The address mail is sent from."""
  fromEmail: String
  """The name mail is sent from."""
  fromName: String
  """The address replies go to."""
  replyToEmail: String
  """The SMTP server."""
  smtpHost: String
  """The SMTP password. It is write-only."""
  smtpPassword: String
  """The SMTP port."""
  smtpPort: String
  """True to use a secure connection."""
  smtpSecure: Boolean
  """The SMTP user name."""
  smtpUsername: String
}

"""Switches on two-factor sign in."""
input EnableTwoFactorInput {
  """A name for the device."""
  deviceName: String
  """The code from the authenticator app."""
  token: String!
}

"""
Stops one of the organization's own dated rates. History is never deleted.
"""
input EndTenantExchangeRateInput {
  """When it stops applying; omitted = now. Never in the past."""
  effectiveTo: DateTime
  """The ID of the rate."""
  id: ID!
}

"""
A B2B spec attribute (e.g. "Resolution" → "1366x768"). Web-verified only.
"""
type EnrichmentAttribute {
  """The name of the attribute."""
  name: String!
  """The value of the attribute."""
  value: String!
}

"""A brand suggested for a product."""
type EnrichmentBrandSuggestion {
  """True when no existing brand matches and one would be created on apply"""
  isNew: Boolean!
  """Id of an existing brand this matches (null when isNew is true)"""
  matchedBrandId: ID
  """Inferred / matched brand name"""
  name: String!
}

"""A category suggested for a product."""
type EnrichmentCategorySuggestion {
  "The unique ID of this record."
  id: ID!
  """The name of the category."""
  name: String!
  """
  Full hierarchy path, e.g. "Grocery/Rice/Basmati"
  """
  path: String
}

"""
How much live web research the AI does. Higher depth = more reliable images/specs but higher AI-credit cost. The seller picks this per product.
"""
enum EnrichmentDepth {
  """Fills the essential details only."""
  BASIC
  """Researches as much as it can find."""
  DEEP
  """Fills the usual set of details."""
  STANDARD
}

"""
Physical dimensions/weight, web-verified only (null fields when not confidently known). Length/width/height are in centimetres; weight is in kilograms.
"""
type EnrichmentDimensions {
  """Height in cm"""
  height: Float
  """Length in cm"""
  length: Float
  """Weight in kg"""
  weight: Float
  """Width in cm"""
  width: Float
}

"""An image found for a product."""
type EnrichmentImageCandidate {
  """The title of the page the image came from."""
  sourceTitle: String
  """The URL of the page the image came from."""
  sourceUrl: String
  """Validated public image URL (image/* content-type, <= 5MB)"""
  url: String!
}

"""
An async product-enrichment job. Returned immediately by startProductEnrichment; poll productEnrichmentJob(jobId) until status is COMPLETED (read suggestion) or FAILED (read error). Replaces the request-blocking enrichProduct path, which exceeded the client HTTP timeout.
"""
type EnrichmentJob {
  """Failure reason. Present only when status is FAILED."""
  error: String
  """The ID of the job."""
  jobId: ID!
  """Where the job stands."""
  status: EnrichmentJobStatus!
  """The enrichment result. Present only when status is COMPLETED."""
  suggestion: ProductEnrichmentSuggestion
}

"""Lifecycle of an async product-enrichment job."""
enum EnrichmentJobStatus {
  """Finished successfully."""
  COMPLETED
  """Stopped with an error."""
  FAILED
  """Queued and not started."""
  PENDING
  """In progress."""
  RUNNING
}

"""
A best-matching existing unit of measure for the product, or null if none fit.
"""
type EnrichmentUnitSuggestion {
  "The unique ID of this record."
  id: ID!
  """The name of the unit."""
  name: String!
  """The symbol of the unit."""
  symbol: String!
}

"""The current exchange rate between two currencies."""
type ExchangeRate {
  "When the record was created."
  createdAt: DateTime!
  """The currency being converted from."""
  fromCurrency: String!
  "The unique ID of this record."
  id: ID!
  """The rate the other way round."""
  inverseRate: Float
  """When the rate was last updated."""
  lastUpdated: DateTime!
  """How much of the target currency one unit of the source is worth."""
  rate: Float!
  """Where the rate came from."""
  source: String
  """The currency being converted to."""
  toCurrency: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""The organizations a person already belongs to."""
type ExistingOrganizationsResponse {
  """The URL of the person's picture."""
  avatar: String
  "Email address."
  email: String
  """True when the person already belongs to an organization."""
  hasExistingOrganizations: Boolean!
  """The person's name."""
  name: String
  """The organizations."""
  organizations: [UserOrganizationInfo!]!
}

"""Expenses in one category."""
type ExpenseCategory {
  """The amount."""
  amount: Float!
  """The name of the category."""
  category: String!
  """Its share of all expenses, in percent."""
  percentage: Float!
}

"""A batch of stock that is close to expiring."""
type ExpiringBatch {
  """The batch number."""
  batchNumber: String
  """The date the batch expires."""
  expiryDate: DateTime!
  """The name of the product."""
  productName: String!
  """The quantity in the batch."""
  quantity: Float!
  """The SKU of the variant."""
  variantSku: String!
  """The name of the warehouse holding it."""
  warehouseName: String!
}

"""The result of extending a session."""
type ExtendSessionResponse {
  """When the session now ends."""
  expiresAt: DateTime!
  """The session token."""
  sessionToken: String!
}

"""A home section showing a festive banner."""
type FestiveBannerSection {
  """Where the button leads."""
  ctaHref: String
  """The text of the button."""
  ctaLabel: String
  """The URL of the banner image."""
  imageUrl: String
  """The kind of home section."""
  kind: HomeSectionKind!
  """The subtitle of the banner."""
  subtitle: String
  """The title of the banner."""
  title: String
}

"""Available filter operators"""
enum FilterOperator {
  """The value contains the text."""
  CONTAINS
  """The value ends with the text."""
  ENDS_WITH
  """The value equals the given value."""
  EQUALS
  """The value is greater than the given value."""
  GT
  """The value is greater than or equal to the given value."""
  GTE
  """The value is one of the listed values."""
  IN
  """The value is less than the given value."""
  LT
  """The value is less than or equal to the given value."""
  LTE
  """The value does not equal the given value."""
  NOT
  """The value is none of the listed values."""
  NOT_IN
  """The value starts with the text."""
  STARTS_WITH
}

"""Financial figures for the period."""
type FinancialAnalytics {
  """What is owed to vendors."""
  accountsPayable: Float!
  """What customers owe."""
  accountsReceivable: Float!
  """The cash flow."""
  cashFlow: Float!
  """The expenses."""
  expenses: Float!
  """The gross margin, in percent."""
  grossMargin: Float!
  """The profit: revenue minus expenses."""
  profit: Float!
  """Profit split by category."""
  profitByCategory: [CategoryProfit!]!
  """The profit as a percent of revenue."""
  profitMargin: Float!
  """The revenue."""
  revenue: Float!
  """Revenue, expenses and profit over time."""
  revenueByPeriod: [RevenueData!]!
  """The categories with the largest expenses."""
  topExpenseCategories: [ExpenseCategory!]!
}

"""
Input to overwrite a purchase order regardless of its status. Fields left out are unchanged.
"""
input ForceUpdatePurchaseOrderInput {
  """
  Alternative tax rate applied to the order, when it differs from the per-line rates.
  """
  alternativeTaxRate: String
  """Cost tier the supplier prices were taken from."""
  costTier: String
  """Address the supplier delivers to, as a JSON address object."""
  deliveryAddress: JSON
  """Free-text delivery instructions for the supplier."""
  deliveryInstructions: String
  """Order-level discount, in the order currency."""
  discountAmount: Float
  """
  Exchange rate between the order currency and the organization's base currency.
  """
  exchangeRate: Float
  """Date the goods are expected to arrive."""
  expectedDate: DateTime
  """Optimistic-concurrency counter — the version the editor loaded."""
  expectedVersion: Int
  """Freight charge for the order, in the order currency."""
  freightAmount: Float
  """The ID of the purchase order to update."""
  id: ID!
  """Comments for your team only; never shown to the supplier."""
  internalComments: String
  """The lines on the order."""
  items: [ForceUpdatePurchaseOrderItemInput!]
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes on the order, visible to the supplier."""
  notes: String
  """Currency code of the order's amounts."""
  orderCurrency: String
  """Date the order was placed."""
  orderDate: String
  """Payment terms agreed with the supplier."""
  paymentTerms: String
  """Project the purchase is for, if any."""
  projectName: String
  """
  Address the order is shipped from or billed to, as a JSON address object.
  """
  shippingAddress: JSON
  """Shipping charge for the order, in the order currency."""
  shippingAmount: Float
  """The supplier's code."""
  supplierCode: String
  """The supplier's display name."""
  supplierDisplayName: String
  """The supplier's email address."""
  supplierEmail: String
  "The ID of the supplier."
  supplierId: String
  """The supplier's legal name."""
  supplierName: String
  """The supplier's phone number."""
  supplierPhone: String
  """Surcharge on the order, in the order currency."""
  surchargeAmount: Float
  """Carrier tracking code for the shipment."""
  trackingCode: String
  "The ID of the warehouse."
  warehouseId: String
}

"""A line on a purchase order being force-updated."""
input ForceUpdatePurchaseOrderItemInput {
  """Discount on this line, as a percentage."""
  discountPercent: Float! = 0
  """The ID of the unit of measure the line is stocked in."""
  inventoryUOMId: String
  """Notes on this line."""
  notes: String
  "The ID of the product."
  productId: String!
  """Quantity ordered, in the line's unit of measure."""
  quantity: Float!
  """Shipping charge allocated to this line."""
  shippingAmount: Float! = 0
  """Surcharge allocated to this line."""
  surchargeAmount: Float! = 0
  """Tax rate on this line, as a percentage."""
  taxRate: Float! = 0
  """Price per unit, in the order currency."""
  unitPrice: Float!
  "The ID of the unit of measure."
  uomId: String!
  "The ID of the product variant."
  variantId: String!
}

"""Asks for a password reset link."""
input ForgotPasswordInput {
  "Email address."
  email: String!
  """
  The subdomain of the organization the reset is for. An email is unique within one organization, so a person in several needs this.
  """
  subdomain: String
}

"""One stage of a funnel."""
type FunnelStage {
  """How many documents reached the stage."""
  count: Int!
  """The name of the stage."""
  stage: String!
  """Their value."""
  value: Float!
}

"""
A goods receipt note: goods received from a vendor into a warehouse, usually against a purchase order.
"""
type GRN {
  """
  The total in the organization's base currency, frozen when the receipt was written. Null on older receipts.
  """
  baseTotalAmount: Float
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String!
  """True when damage was reported on delivery."""
  damageReported: Boolean!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The date the goods arrived."""
  deliveryDate: DateTime!
  """The name of the driver who delivered the goods."""
  driverName: String
  "The ID of the user who created the record."
  enteredBy: String!
  """
  The rate frozen when the receipt was written: 1 unit of the receipt currency in the organization's base currency.
  """
  exchangeRate: Float
  """The date the goods were expected."""
  expectedDate: DateTime
  """The receipt number, unique within the organization."""
  grnNumber: String!
  "The unique ID of this record."
  id: ID!
  """When the goods were inspected."""
  inspectedAt: DateTime
  """The ID of the user who inspected the goods."""
  inspectedBy: ID
  """The user who inspected the goods."""
  inspector: GRNUser
  """The lines of the receipt."""
  items: [GRNItem!]!
  """The days between the order date and the delivery date."""
  leadTimeActual: Int
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """Notes about the receipt."""
  notes: String
  """The date the purchase order was placed."""
  orderDate: DateTime
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The purchase order the goods were received against."""
  purchaseOrder: GRNPurchaseOrder
  "The ID of the purchase order."
  purchaseOrderId: ID
  """An overall quality score for the delivery."""
  qualityScore: Float
  """A reference to the delivery document."""
  receiptDocument: String
  """The user who received the goods."""
  receiver: GRNUser
  """True when a shortage was reported on delivery."""
  shortageReported: Boolean!
  """
  The receipt status: DRAFT, CONFIRMED, PARTIALLY_RECEIVED, RECEIVED or COMPLETED.
  """
  status: String!
  """The receipt amount before tax, in the receipt currency."""
  subtotal: Float!
  """The tax on the receipt."""
  taxAmount: Float!
  """The total quantity accepted."""
  totalAcceptedQuantity: Float!
  """The receipt total including tax, in the receipt currency."""
  totalAmount: Float!
  """How many lines the receipt has."""
  totalItemsCount: Int!
  """The total quantity that arrived."""
  totalReceivedQuantity: Float!
  """The total quantity rejected."""
  totalRejectedQuantity: Float!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The registration number of the delivery vehicle."""
  vehicleNumber: String
  """The vendor that delivered the goods."""
  vendor: GRNVendor
  """The ID of the vendor that delivered the goods."""
  vendorPartnerId: ID!
  """The warehouse that received the goods."""
  warehouse: GRNWarehouse
  "The ID of the warehouse."
  warehouseId: ID!
}

"""Filters and sorting for the goods receipt list."""
input GRNFilterInput {
  "ISO 4217 currency code."
  currency: String
  """Only receipts where damage was reported, or not."""
  damageReported: Boolean
  """Only receipts delivered on or after this date."""
  deliveryDateFrom: String
  """Only receipts delivered on or before this date."""
  deliveryDateTo: String
  """Only the receipt with this number."""
  grnNumber: String
  """Only receipts inspected by this user."""
  inspectedBy: String
  """Only receipts with a quality score at or below this."""
  maxQualityScore: Float
  """Only receipts with a quality score at or above this."""
  minQualityScore: Float
  """Only receipts whose order is dated on or after this date."""
  orderDateFrom: String
  """Only receipts whose order is dated on or before this date."""
  orderDateTo: String
  "The ID of the purchase order."
  purchaseOrderId: String
  "Text to search for."
  search: String
  """Only receipts where a shortage was reported, or not."""
  shortageReported: Boolean
  """The column to sort by. Defaults to newest delivery first."""
  sortBy: GRNSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only receipts in this status."""
  status: String
  """Only receipts from this vendor."""
  vendorPartnerId: String
  "The ID of the warehouse."
  warehouseId: String
}

"""One line of a goods receipt."""
type GRNItem {
  """The accepted quantity as a percent of the ordered quantity."""
  acceptedPercentage: Float!
  """The quantity accepted after inspection."""
  acceptedQuantity: Float!
  """The batch number of the stock."""
  batchNumber: String
  "When the record was created."
  createdAt: DateTime!
  """How many damaged units were found."""
  damageCount: Int!
  """How many defective units were found."""
  defectCount: Int!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The discount amount, worked out from the percent."""
  discountAmount: Float!
  """The discount carried from the purchase order line, in percent."""
  discountPercent: Float!
  "The ID of the user who created the record."
  enteredBy: String!
  """The date the stock expires."""
  expiryDate: DateTime
  """The ID of the goods receipt the line belongs to."""
  grnId: ID!
  "The unique ID of this record."
  id: ID!
  """The quantity already billed on a purchase invoice."""
  invoicedQuantity: Float!
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """Notes about the line."""
  notes: String
  """The quantity ordered."""
  orderedQuantity: Float!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The product received."""
  product: GRNItemProduct
  "The ID of the product."
  productId: ID!
  """The quality grade given to the line."""
  qualityGrade: String
  """The received quantity as a percent of the ordered quantity."""
  receivedPercentage: Float!
  """The quantity that arrived."""
  receivedQuantity: Float!
  """The rejected quantity as a percent of the ordered quantity."""
  rejectedPercentage: Float!
  """The quantity rejected."""
  rejectedQuantity: Float!
  """
  The quantity still to bill: accepted less returned less invoiced, never below zero. Only set when a single receipt is fetched.
  """
  remainingQuantity: Float
  """
  The quantity that can still be returned to the vendor: accepted less earlier purchase returns. Only set when a single receipt is fetched.
  """
  returnableQuantity: Float
  """
  The quantity sent back to the vendor on live purchase returns. Only set when a single receipt is fetched.
  """
  returnedQuantity: Float
  """The tax rate carried from the purchase order line, in percent."""
  taxRate: Float!
  """The line cost, in the receipt currency."""
  totalCost: Float!
  """The cost of one unit, in the receipt currency."""
  unitCost: Float!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The variant received."""
  variant: GRNItemVariant
  "The ID of the product variant."
  variantId: ID!
  """The vendor product received."""
  vendorProduct: GRNItemVendorProduct
  """The ID of the vendor product the line is for."""
  vendorProductId: ID
}

"""The product on a goods receipt line."""
type GRNItemProduct {
  """The product barcode."""
  barcode: String
  "The unique ID of this record."
  id: ID!
  """True when the product is exempt from tax."""
  isTaxExempt: Boolean
  """The product name."""
  name: String!
  """The product SKU."""
  sku: String
  """The tax rate on the product."""
  taxRate: GRNItemTaxRate
}

"""A tax rate on a product."""
type GRNItemTaxRate {
  "The unique ID of this record."
  id: ID!
  """The name of the tax rate."""
  name: String!
  """The rate, in percent."""
  rate: Float!
}

"""The product variant on a goods receipt line."""
type GRNItemVariant {
  """The variant barcode."""
  barcode: String
  "The unique ID of this record."
  id: ID!
  """The variant name. Empty when the variant has only a SKU."""
  name: String
  """The variant SKU."""
  sku: String!
}

"""The vendor product on a goods receipt line."""
type GRNItemVendorProduct {
  """The average cost of one unit across receipts."""
  averageCost: Float
  "The unique ID of this record."
  id: ID!
  """The cost of one unit on the last receipt."""
  lastCost: Float
  """The vendor's name for the product."""
  vendorName: String
  """The vendor's code for the product."""
  vendorSku: String!
}

"""The purchase order a goods receipt is against."""
type GRNPurchaseOrder {
  """The discount on the order."""
  discountAmount: Float
  """The date the goods were expected."""
  expectedDate: DateTime
  "The unique ID of this record."
  id: ID!
  """The date the order was placed."""
  orderDate: DateTime!
  """The purchase order number."""
  orderNumber: String!
  """The payment terms on the order."""
  paymentTerms: String
  """The shipping charge on the order."""
  shippingAmount: Float
  """The status of the purchase order."""
  status: String!
  """The order amount before tax."""
  subtotal: Float
  """The surcharge on the order."""
  surchargeAmount: Float
  """The tax on the order."""
  taxAmount: Float
  """The order total including tax."""
  totalAmount: Float
}

"""A column the goods receipt list can be sorted by."""
enum GRNSortField {
  """When the receipt was created."""
  CREATED_AT
  """The delivery date."""
  DELIVERY_DATE
  """The total amount."""
  TOTAL_AMOUNT
}

"""
Totals for the goods receipt list, in the organization's base currency. A receipt's value includes its share of the purchase order's shipping and surcharge.
"""
type GRNSummary {
  """How many have at least one accepted line."""
  acceptedGRNs: Int!
  """The value of counted receipts that have an accepted line."""
  acceptedValue: Float!
  """The value of counted receipts on approved purchase orders."""
  approvedPoValue: Float!
  """How many are drafts."""
  draftGRNs: Int!
  """
  How many are received, leaving out those on purchase orders that can no longer be received.
  """
  receivedGRNs: Int!
  """The value of those received receipts."""
  receivedValue: Float!
  """How many receipts there are."""
  totalGRNs: Int!
  """
  The value of all counted receipts: not drafts, and not on purchase orders that can no longer be received.
  """
  totalValue: Float!
  """
  The value of receipts on purchase orders that can no longer be received. These are left out of the other values.
  """
  unreceivablePoValue: Float!
  """The value of counted receipts that have no purchase order."""
  withoutPoValue: Float!
}

"""A user named on a goods receipt."""
type GRNUser {
  "Email address."
  email: String!
  """The user's first name."""
  firstName: String!
  "The unique ID of this record."
  id: ID!
  """The user's last name."""
  lastName: String!
}

"""The vendor on a goods receipt."""
type GRNVendor {
  """The vendor code."""
  code: String!
  """The name to show for the vendor."""
  displayName: String
  "The unique ID of this record."
  id: ID!
  """The vendor name."""
  name: String!
}

"""The warehouse that received the goods."""
type GRNWarehouse {
  """The warehouse code."""
  code: String!
  "The unique ID of this record."
  id: ID!
  """The warehouse name."""
  name: String!
}

"""
The result of a GDPR data export. The file lives in storage and is not returned in the response, which could be very large.
"""
type GdprExportResult {
  """
  Count of tenant-adjacent (org-less child) models exported via their scoped parent.
  """
  adjacentModelCount: Int!
  """Time-limited presigned URL to download the NDJSON export artifact."""
  downloadUrl: String!
  """Seconds until the presigned download URL expires."""
  expiresInSeconds: Int!
  """Object-storage key of the export artifact."""
  objectName: String!
  """JSON map of model name → exported row count (diagnostic)."""
  perModelCounts: String!
  """Total number of rows written across all models."""
  recordCount: Int!
  """Count of directly org-scoped models exported."""
  scopedModelCount: Int!
}

"""Creates a payout for a period."""
input GeneratePayoutInput {
  """The period to pay out."""
  period: String!
  "The ID of the user."
  userId: String!
}

"""
Generates the full route plan of one cycle for one rep. It covers the customers whose visit frequency equals the cycle length.
"""
input GenerateRoutePlanInput {
  """
  The visit frequency group to generate, and the number of working days the cycle spans.
  """
  cycleLengthDays: Int!
  """
  The first day of the cycle. The plan starts on the rep's first working day on or after it.
  """
  cycleStartDate: DateTime!
  """
  True to treat this cycle as a seven-day week with Sunday included, for this call only. The organization's setting is not changed.
  """
  includeSundays: Boolean
  """The ID of the rep."""
  salesRepId: String!
}

"""The route plans created or updated, and the customers who did not fit."""
type GenerateRoutePlanResult {
  """The customers who were due but did not fit."""
  deferred: [DeferredVisitCustomer!]!
  """The day plans."""
  plans: [JourneyPlan!]!
}

"""What to generate a SKU from."""
input GenerateSKUInput {
  "The ID of the brand."
  brandId: String
  "The ID of the category."
  categoryId: String
  """Values for custom placeholders in the pattern."""
  customVariables: JSON
  """A prefix to use when no pattern matches."""
  prefix: String
}

"""A generated SKU."""
type GeneratedSKU {
  """Why a SKU could not be generated."""
  error: String
  """True when a SKU could be generated."""
  isValid: Boolean!
  """The generated SKU."""
  sku: String!
}

"""
Column-mapping ruleset for a generic product import: a known supplier layout (SMTT) or header-detected (CUSTOM).
"""
enum GenericImportMappingProfile {
  """Columns are matched from the file's headers."""
  CUSTOM
  """The known SMTT supplier layout."""
  SMTT
}

"""
A dry run of a generic product import: what would be written, and the organization defaults that were applied.
"""
type GenericProductImportPreview {
  """How many products would be created."""
  createCount: Int!
  "ISO 4217 currency code."
  currency: String
  """A temporary handle to pass back when approving the import."""
  importId: String!
  """
  The minimum order quantity applied to imported variants. It may be fractional.
  """
  moq: Float!
  """A few valid rows, to show what the import will do."""
  sampleRows: [GenericProductImportSampleRow!]!
  """How many variants would be created."""
  variantCount: Int!
  """Non-blocking issues to review before approving."""
  warnings: [String!]!
}

"""
One valid row of a product import, shown at the approval step. Only a bounded sample is returned.
"""
type GenericProductImportSampleRow {
  """The cost of one unit."""
  cost: Float!
  """The list price."""
  price: Float!
  """The name of the product."""
  productName: String!
  """The sale price."""
  salePrice: Float!
  """The SKU of the variant."""
  sku: String!
  """The name of the variant."""
  variantName: String!
}

"""Which settings to list."""
input GetTenantSettingsInput {
  """Only settings in this group."""
  categoryFilter: SettingCategory
  """Further filters."""
  filter: TenantSettingFilterInput
  """True to include the default settings."""
  includeDefaults: Boolean = false
  """Which page to return."""
  pagination: PaginationInput
  """How to sort."""
  sort: [SortInput!]
}

"""Which users to list."""
input GetUsersInput {
  """Filters."""
  filter: UserFilterInput
  """Which page to return."""
  pagination: PaginationInput
  """How to sort."""
  sort: [SortInput!]
}

"""A brand that matched."""
type GlobalSearchBrandFullResult {
  """What the brand is."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The name of the brand."""
  name: String!
}

"""A brand shown inside another result."""
type GlobalSearchBrandResult {
  """The name of the brand."""
  name: String!
}

"""A category that matched."""
type GlobalSearchCategoryFullResult {
  """What the category holds."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The name of the category."""
  name: String!
}

"""A category shown inside another result."""
type GlobalSearchCategoryResult {
  """The name of the category."""
  name: String!
}

"""A credit note that matched."""
type GlobalSearchCreditNoteResult {
  """The credit note amount."""
  amount: Float!
  """The credit note number."""
  creditNoteNumber: String!
  "ISO 4217 currency code."
  currency: String!
  "The unique ID of this record."
  id: ID!
  """The date the note was issued."""
  issueDate: DateTime!
  """The status of the note."""
  status: String!
}

"""A customer that matched."""
type GlobalSearchCustomerResult {
  """The name of the customer's company."""
  companyName: String
  "Email address."
  email: String
  """The contact's first name."""
  firstName: String
  "The unique ID of this record."
  id: ID!
  """The contact's last name."""
  lastName: String
  "Phone number."
  phone: String
}

"""A debit note that matched."""
type GlobalSearchDebitNoteResult {
  """The debit note amount."""
  amount: Float!
  "ISO 4217 currency code."
  currency: String!
  """The debit note number."""
  debitNoteNumber: String!
  "The unique ID of this record."
  id: ID!
  """The date the note was issued."""
  issueDate: DateTime!
  """The status of the note."""
  status: String!
}

"""A discount scheme that matched."""
type GlobalSearchDiscountResult {
  """What the scheme is for."""
  description: String
  """How the discount is worked out."""
  discountType: String!
  """The percentage or the fixed amount."""
  discountValue: Float!
  "The unique ID of this record."
  id: ID!
  """The name of the scheme."""
  name: String!
}

"""A goods receipt that matched."""
type GlobalSearchGRNResult {
  """The receipt number."""
  grnNumber: String!
  "The unique ID of this record."
  id: ID!
  """The date the goods were received."""
  receivedDate: DateTime!
  """The status of the receipt."""
  status: String!
  """The supplier."""
  supplier: GlobalSearchSupplierResult
}

"""A stock row that matched."""
type GlobalSearchInventoryResult {
  """The quantity on hand."""
  currentStock: Float!
  "The unique ID of this record."
  id: ID!
  """The product."""
  product: GlobalSearchProductResult
  """The quantity held by confirmed orders."""
  reservedStock: Float!
  """The warehouse."""
  warehouse: GlobalSearchWarehouseResult
}

"""An invoice found by global search."""
type GlobalSearchInvoiceResult {
  "ISO 4217 currency code."
  currency: String!
  "The unique ID of this record."
  id: ID!
  """The date of the invoice."""
  invoiceDate: DateTime!
  """The invoice number."""
  invoiceNumber: String!
  """The status of the invoice."""
  status: String!
  """The invoice total."""
  totalAmount: Float!
  """The kind of invoice: sales or purchase."""
  type: String!
}

"""A payment that matched."""
type GlobalSearchPaymentResult {
  """The amount."""
  amount: Float!
  "ISO 4217 currency code."
  currency: String!
  "The unique ID of this record."
  id: ID!
  """The date of the payment."""
  paymentDate: DateTime!
  """How it was paid."""
  paymentMethod: String!
  """The payment number."""
  paymentNumber: String!
  """
  COLLECTION for a customer payment, PAYMENT for a supplier payment. Together with the method it tells the kind of result.
  """
  type: PaymentType!
}

"""A product that matched."""
type GlobalSearchProductResult {
  """The barcode of the product."""
  barcode: String
  """The brand of the product."""
  brand: GlobalSearchBrandResult
  """The category of the product."""
  category: GlobalSearchCategoryResult
  """What the product is."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The name of the product."""
  name: String!
  """The SKU of the product."""
  sku: String
}

"""A purchase order that matched."""
type GlobalSearchPurchaseOrderResult {
  "ISO 4217 currency code."
  currency: String!
  "The unique ID of this record."
  id: ID!
  """The date of the order."""
  orderDate: DateTime!
  """The order number."""
  orderNumber: String!
  """The status of the order."""
  status: String!
  """The supplier."""
  supplier: GlobalSearchSupplierResult
  """The order total."""
  totalAmount: Float!
}

"""A quote that matched."""
type GlobalSearchQuoteResult {
  "ISO 4217 currency code."
  currency: String!
  """The customer."""
  customer: GlobalSearchCustomerResult
  "The unique ID of this record."
  id: ID!
  """The date of the quote."""
  quoteDate: DateTime!
  """The quote number."""
  quoteNumber: String!
  """The status of the quote."""
  status: String!
  """The quote total."""
  totalAmount: Float!
}

"""The results of a search across the whole application, grouped by kind."""
type GlobalSearchResult {
  """The matching brands."""
  brands: [GlobalSearchBrandFullResult!]!
  """The matching categories."""
  categories: [GlobalSearchCategoryFullResult!]!
  """The matching credit notes."""
  creditNotes: [GlobalSearchCreditNoteResult!]!
  """The matching customers."""
  customers: [GlobalSearchCustomerResult!]!
  """The matching debit notes."""
  debitNotes: [GlobalSearchDebitNoteResult!]!
  """The matching discount schemes."""
  discounts: [GlobalSearchDiscountResult!]!
  """The matching goods receipts."""
  grns: [GlobalSearchGRNResult!]!
  """The matching stock rows."""
  inventory: [GlobalSearchInventoryResult!]!
  """The matching invoices."""
  invoices: [GlobalSearchInvoiceResult!]!
  """The matching payments."""
  payments: [GlobalSearchPaymentResult!]!
  """The matching products."""
  products: [GlobalSearchProductResult!]!
  """The matching purchase orders."""
  purchaseOrders: [GlobalSearchPurchaseOrderResult!]!
  """The matching sales orders."""
  salesOrders: [GlobalSearchSalesOrderResult!]!
  """The matching quotes."""
  salesQuotes: [GlobalSearchQuoteResult!]!
  """The matching stock adjustments."""
  stockAdjustments: [GlobalSearchStockAdjustmentResult!]!
  """The matching stock alerts."""
  stockAlerts: [GlobalSearchStockAlertResult!]!
  """The matching stock movements."""
  stockMovements: [GlobalSearchStockMovementResult!]!
  """The matching suppliers."""
  suppliers: [GlobalSearchSupplierResult!]!
  """The matching tax groups."""
  taxGroups: [GlobalSearchTaxGroupResult!]!
  """The matching tax rates."""
  taxRates: [GlobalSearchTaxRateResult!]!
  """The matching warehouses."""
  warehouses: [GlobalSearchWarehouseFullResult!]!
}

"""A sales order that matched."""
type GlobalSearchSalesOrderResult {
  "ISO 4217 currency code."
  currency: String!
  """The customer."""
  customer: GlobalSearchCustomerResult
  "The unique ID of this record."
  id: ID!
  """The date of the order."""
  orderDate: DateTime!
  """The order number."""
  orderNumber: String!
  """The status of the order."""
  status: String!
  """The order total."""
  totalAmount: Float!
}

"""A stock adjustment that matched."""
type GlobalSearchStockAdjustmentResult {
  """The date of the adjustment."""
  adjustmentDate: DateTime!
  """The adjustment number."""
  adjustmentNumber: String!
  "The unique ID of this record."
  id: ID!
  """The product."""
  product: GlobalSearchProductResult
  """The quantity adjusted."""
  quantity: Float!
  """The kind of adjustment."""
  type: String!
  """The warehouse."""
  warehouse: GlobalSearchWarehouseResult
}

"""A stock alert that matched."""
type GlobalSearchStockAlertResult {
  """How serious the alert is."""
  alertLevel: String!
  """The quantity on hand."""
  currentStock: Float!
  "The unique ID of this record."
  id: ID!
  """The lowest quantity the stock should hold."""
  minStock: Float!
  """The product."""
  product: GlobalSearchProductResult
  """The warehouse."""
  warehouse: GlobalSearchWarehouseResult
}

"""A stock movement that matched."""
type GlobalSearchStockMovementResult {
  """The warehouse the stock leaves."""
  fromWarehouse: GlobalSearchWarehouseResult
  "The unique ID of this record."
  id: ID!
  """The movement number."""
  movementNumber: String!
  """The product."""
  product: GlobalSearchProductResult
  """The quantity moved."""
  quantity: Float!
  """The status of the movement."""
  status: String!
  """The warehouse the stock goes to."""
  toWarehouse: GlobalSearchWarehouseResult
  """The kind of movement."""
  type: String!
}

"""A supplier that matched."""
type GlobalSearchSupplierResult {
  """The supplier's contact person."""
  contactPerson: String
  "Email address."
  email: String
  "The unique ID of this record."
  id: ID!
  """The name of the supplier."""
  name: String!
  "Phone number."
  phone: String
}

"""A tax group that matched."""
type GlobalSearchTaxGroupResult {
  """What the tax group is for."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The name of the tax group."""
  name: String!
}

"""A tax rate that matched."""
type GlobalSearchTaxRateResult {
  "The unique ID of this record."
  id: ID!
  """The name of the tax rate."""
  name: String!
  """The rate, in percent."""
  rate: Float!
  """The kind of tax."""
  taxType: String!
}

"""Types of entities to search for"""
enum GlobalSearchType {
  """Brands."""
  BRAND
  """Categories."""
  CATEGORY
  """Credit notes."""
  CREDIT_NOTE
  """Customers."""
  CUSTOMER
  """Debit notes."""
  DEBIT_NOTE
  """Discount schemes."""
  DISCOUNT
  """Goods receipt notes."""
  GRN
  """Inventory records."""
  INVENTORY
  """Invoices."""
  INVOICE
  """Payments."""
  PAYMENT
  """Pricing tiers."""
  PRICING_TIER
  """Products."""
  PRODUCT
  """Purchase orders."""
  PURCHASE_ORDER
  """Sales orders."""
  SALES_ORDER
  """Quotes."""
  SALES_QUOTE
  """Stock adjustments."""
  STOCK_ADJUSTMENT
  """Stock alerts."""
  STOCK_ALERT
  """Stock movements."""
  STOCK_MOVEMENT
  """Suppliers."""
  SUPPLIER
  """Tax groups."""
  TAX_GROUP
  """Tax rates."""
  TAX_RATE
  """Warehouses."""
  WAREHOUSE
}

"""A warehouse that matched."""
type GlobalSearchWarehouseFullResult {
  """The address of the warehouse."""
  address: String
  """The warehouse code."""
  code: String
  "The unique ID of this record."
  id: ID!
  """The name of the warehouse."""
  name: String!
}

"""A warehouse shown inside another result."""
type GlobalSearchWarehouseResult {
  """The name of the warehouse."""
  name: String!
}

"""The result of signing in with Google."""
type GoogleAuthResponse {
  """The token to send with requests."""
  accessToken: String
  """True when the person was signed in."""
  authenticated: Boolean
  """Who is signing up, when sign up is needed."""
  pendingUser: PendingGoogleUser
  """The token to get a new access token."""
  refreshToken: String
  """The token that identifies the session."""
  sessionToken: String
  """True when the person has no account yet and must sign up."""
  signupRequired: Boolean
  """The signed-in user."""
  user: User
}

"""Creates an organization from a Google sign in."""
input GoogleRegisterInput {
  """The name of the company."""
  companyName: String!
  """The country."""
  country: String!
  "ISO 4217 currency code."
  currency: String
  """The date format."""
  dateFormat: String
  """The token from Google."""
  googleToken: String!
  """The language."""
  language: String
  """The subdomain for the organization."""
  subdomain: String!
  """The time zone."""
  timezone: String
}

"""The result of creating an organization from a Google sign in."""
type GoogleRegisterResponse {
  """The token to send with requests."""
  accessToken: String
  """A message about the outcome."""
  message: String
  """Onboarding session ID for SSE progress tracking"""
  onboardingId: String
  """The new organization."""
  organization: Organization
  """The token to get a new access token."""
  refreshToken: String
  """True when it was created."""
  success: Boolean!
  """If true, client should subscribe to SSE for progress"""
  useAsyncOnboarding: Boolean
  """The new user."""
  user: User
}

"""Whether picks are staged and added together, or added at once"""
enum GuidedAddMode {
  """Each pick is added to the cart at once."""
  IMMEDIATE
  """Picks are collected and added together."""
  STAGED
}

"""One variant attribute of the catalog, as a guided step could use it"""
type GuidedAttributeKey {
  """
  The spelling most variants use; other spellings fold into it the way a step matches them
  """
  key: String!
  """Values in natural order"""
  values: [GuidedAttributeValue!]!
  """True when more values exist than were returned"""
  valuesTruncated: Boolean!
  """How many variants have the attribute."""
  variantCount: Int!
}

"""A value of a variant attribute and how many variants have it."""
type GuidedAttributeValue {
  """The value."""
  value: String!
  """How many variants have it."""
  variantCount: Int!
}

"""The guided flow a category opens."""
type GuidedCategoryEntry {
  "The ID of the category."
  categoryId: ID!
  """The ID of the flow."""
  flowId: ID!
}

"""A fixed choice in a guided step."""
type GuidedChoice {
  """The URL of an image for the choice."""
  imageUrl: String
  """The text to show."""
  label: String!
  """The products the choice narrows to."""
  scope: GuidedFlowScope
  """Keys of the later steps that follow this branch"""
  steps: [String!]
  """The value sent back when it is chosen."""
  value: String!
}

"""The category a 'View all' link on a guided step opens"""
type GuidedContextCategory {
  """The category code."""
  code: String!
  "The unique ID of this record."
  id: ID!
  """The name of the category."""
  name: String!
}

"""
What the buyer tapped to open a guided flow; ignored unless it opens that flow
"""
input GuidedEntryInput {
  """ATTRIBUTE: the attribute the value belongs to"""
  attributeKey: String
  """What the entry matches on."""
  kind: GuidedEntryKind!
  """A category id, brand id, tag or attribute value"""
  value: String!
}

"""
What a buyer can tap to open a guided flow: a category, a brand, a tag or an attribute value
"""
enum GuidedEntryKind {
  """The flow opens from a product attribute value."""
  ATTRIBUTE
  """The flow opens from a brand."""
  BRAND
  """The flow opens from a category."""
  CATEGORY
  """The flow opens from a tag."""
  TAG
}

"""
Which guided flow a tapped category, brand, tag or attribute value opens on the buyer app
"""
type GuidedEntryMap {
  """
  Category LIST rules expanded to every category inside them (the nearest listed one wins)
  """
  categoryEntries: [GuidedCategoryEntry!]!
  """The rules that decide which flow a product opens."""
  rules: [GuidedEntryMapRule!]!
}

"""A buyer flow's 'open from' rule, as the app resolves taps"""
type GuidedEntryMapRule {
  """The attribute the rule matches on, when it matches on one."""
  attributeKey: String
  """
  ALL: the values left out; for categories, with every category inside them
  """
  except: [String!]!
  """The ID of the flow the rule opens."""
  flowId: ID!
  """What the rule matches on."""
  kind: GuidedEntryKind!
  """How the rule matches."""
  mode: GuidedEntryMode!
  """The values the rule matches."""
  values: [String!]!
}

"""
LIST: opens from the rule's values. ALL: from every value no other flow lists, except some.
"""
enum GuidedEntryMode {
  """Opens from every value that no other flow lists, except some."""
  ALL
  """Opens only from the values the rule lists."""
  LIST
}

"""
One 'open from' rule of a guided flow; a category also covers every category inside it
"""
type GuidedEntryRule {
  """ATTRIBUTE: the attribute the values belong to"""
  attributeKey: String
  """ALL: the values left out"""
  except: [String!]!
  """What the rule matches on."""
  kind: GuidedEntryKind!
  """How the rule matches."""
  mode: GuidedEntryMode!
  """LIST: the category ids, brand ids, tags or attribute values"""
  values: [String!]!
}

"""A guided flow that helps a buyer find the right variant step by step."""
type GuidedFlow {
  "The unique ID of this record."
  id: ID!
  """The URL of an image for the flow."""
  imageUrl: String
  """The name of the flow."""
  label: String!
  """
  What opens this flow on the buyer app instead of a listing; empty means only links do
  """
  openFrom: [GuidedEntryRule!]!
  """How the flow behaves."""
  options: GuidedFlowOptions!
  """How the final variants are listed."""
  rows: GuidedRowsConfig!
  """The products the flow covers. Empty means all."""
  scope: GuidedFlowScope
  """The steps of the flow."""
  steps: [GuidedStep!]!
  """Where the flow is offered."""
  surfaces: [GuidedFlowSurface!]!
}

"""How a guided flow behaves."""
type GuidedFlowOptions {
  """Whether picks are staged and added together, or added at once."""
  addMode: GuidedAddMode!
  """How an out-of-stock variant is shown."""
  unavailable: GuidedUnavailableMode!
}

"""The products a guided flow covers."""
type GuidedFlowScope {
  """The IDs of the categories."""
  categoryIds: [ID!]!
}

"""The app a guided flow is offered in"""
enum GuidedFlowSurface {
  """The buyer app and portal."""
  BUYER
  """The sales app."""
  REP
}

"""A choice the buyer made in a guided flow."""
input GuidedPickInput {
  """The step the choice is for."""
  stepKey: String!
  """The value chosen."""
  value: String!
}

"""How the final variants of a guided flow are listed."""
type GuidedRowsConfig {
  """True when rows of different products are told apart by product name."""
  distinguishByProduct: Boolean!
  """The attribute used as the label of each row."""
  labelAttribute: String!
  """
  The attributes the buyer may filter the rows by, in order. Empty offers every attribute that differs between the rows.
  """
  refineAttributes: [String!]!
  """True when each row shows a picture."""
  showPicture: Boolean!
  """True when the rows page offers the filter."""
  showRefine: Boolean!
  """True when the rows page offers a Sort select."""
  showSort: Boolean!
  """True when each row shows the variant's name and its attribute value."""
  showVariantDetail: Boolean!
}

"""One step of a guided flow."""
type GuidedStep {
  """The variant attribute the options come from."""
  attributeKey: String
  """The fixed choices, when the options are choices."""
  choices: [GuidedChoice!]
  """The picture shown for every option that has none of its own."""
  defaultImageUrl: String
  """How the options are shown."""
  display: GuidedStepDisplay!
  """
  CATEGORY: after a pick, ask again among the picked category's children, level by level.
  """
  drillDown: Boolean!
  """The key of the step."""
  key: String!
  """The question to show."""
  label: String!
  """
  CATEGORY: whose children the step offers; null means the top-level categories.
  """
  parentCategoryId: ID
  """True when the step offers a search box."""
  search: Boolean!
  """Where the options come from."""
  source: GuidedStepSource!
  """Images for the values."""
  valueImages: [GuidedValueImage!]
  """The order the values are shown in."""
  valueOrder: [String!]
}

"""How a guided step shows its options: TILES or LIST."""
enum GuidedStepDisplay {
  """Shown as a list."""
  LIST
  """Shown as tiles."""
  TILES
}

"""What a guided flow was opened from, as the server accepted it"""
type GuidedStepEntry {
  """The attribute the entry matches on, when it matches on one."""
  attributeKey: String
  """CATEGORY: root first, ending with the category; else empty"""
  chain: [ID!]!
  """What the entry matches on."""
  kind: GuidedEntryKind!
  """The category or brand name, the tag, or the value"""
  label: String!
  """Steps the entry answered; never shown"""
  preAnsweredStepKeys: [String!]!
  """The value the entry matches."""
  value: String!
}

"""One choice offered in a guided step."""
type GuidedStepOption {
  """True when something matching the choice is available."""
  available: Boolean!
  """The URL of an image for the choice."""
  imageUrl: String
  """The text to show."""
  label: String!
  """How many variants match the choice."""
  matchingVariantCount: Int!
  """Product and variant steps: the product the choice is."""
  productId: ID
  """The value sent back when it is chosen."""
  value: String!
  """
  Variant steps: the variant itself. Product steps: the variant to open the product on.
  """
  variantId: ID
  """
  Product and variant steps: every variant the choice matches so far. Empty for other steps.
  """
  variantIds: [ID!]!
}

"""The next step of a guided flow, or its final result."""
type GuidedStepResult {
  """
  The category a 'View all' link opens: a CATEGORY step's current parent, else the entry category
  """
  contextCategory: GuidedContextCategory
  """How to show the options."""
  display: GuidedStepDisplay
  """The entry in effect; null when none was given or it was ignored"""
  entry: GuidedStepEntry
  """The ID of the flow."""
  flowId: ID!
  """Whether this is a step to answer or the final list of variants."""
  kind: GuidedStepResultKind!
  """The question or title to show."""
  label: String
  """
  True for a product or variant step: it ends the journey, showing its variants as the product list does, and a choice opens the product page.
  """
  opensProduct: Boolean!
  """The choices of the step."""
  options: [GuidedStepOption!]!
  """The matching variants, at the end of the flow."""
  rows: [GuidedVariantRow!]!
  """True when the step offers a search box."""
  search: Boolean!
  """The key of the step."""
  stepKey: String
  """True when more rows matched than were returned"""
  truncated: Boolean!
}

"""Whether a guided step answers with options or variant rows"""
enum GuidedStepResultKind {
  """The step answers with options to pick from."""
  OPTIONS
  """The step answers with variant rows."""
  ROWS
}

"""Where a guided step's options come from"""
enum GuidedStepSource {
  """The options are brands."""
  BRAND
  """The options are categories."""
  CATEGORY
  """The options are fixed choices set in the flow."""
  CHOICE
  """
  The options are the matching products; the step ends the finder on the product list.
  """
  PRODUCT
  """
  The options are the matching variants; the step ends the finder on the product list.
  """
  VARIANT
  """The options are values of a variant attribute."""
  VARIANT_ATTRIBUTE
}

"""How an out-of-stock variant row is shown"""
enum GuidedUnavailableMode {
  """Shown but cannot be added."""
  DISABLED
  """Not shown."""
  HIDDEN
}

"""An image for one value of a step."""
type GuidedValueImage {
  """The URL of the image."""
  imageUrl: String!
  """The value."""
  value: String!
}

"""One attribute value of a variant."""
type GuidedVariantAttribute {
  """The attribute's name, e.g. Colour."""
  name: String!
  """The variant's value of it, e.g. Black."""
  value: String!
}

"""Facts about a variant used by a guided flow."""
type GuidedVariantFacts {
  """The variant's attributes as a flat { rawKey: value } object"""
  attributes: JSON!
  """The product's brand"""
  brandId: ID
  """The product's categories plus all their ancestors"""
  categoryIds: [ID!]!
  "The ID of the product."
  productId: ID!
  """The product's tags"""
  tags: [String!]!
  "The ID of the product variant."
  variantId: ID!
}

"""One variant offered at the end of a guided flow."""
type GuidedVariantRow {
  """The attribute the rows are told apart by, e.g. Colour."""
  attributeName: String
  """This variant's value of that attribute, e.g. Black."""
  attributeValue: String
  """Every attribute of the variant."""
  attributes: [GuidedVariantAttribute!]!
  """True when the variant is available."""
  available: Boolean!
  """The variant's picture, else its attribute value's, else the product's."""
  imageUrl: String
  """The label of the variant."""
  label: String!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The SKU of the variant."""
  sku: String!
  "The ID of the product variant."
  variantId: ID!
  """The variant's own name; null when it has none."""
  variantName: String
}

"""A home section showing a carousel of large slides."""
type HeroCarouselSection {
  """The kind of home section."""
  kind: HomeSectionKind!
  """The slides."""
  slides: [HeroCarouselSlide!]!
}

"""One slide of the hero carousel."""
type HeroCarouselSlide {
  """Where the slide leads."""
  href: String
  "The unique ID of this record."
  id: ID!
  """The URL of the slide image."""
  imageUrl: String
  """The subtitle of the slide."""
  subtitle: String
  """The title of the slide."""
  title: String
}

"""
One customer under a node's subtree, with order figures. The rep is the team member the customer is attributed to.
"""
type HierarchyCustomer {
  """The customer code."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  """The customer's tier."""
  customerTier: String
  "The unique ID of this record."
  id: ID!
  """When the customer last ordered."""
  lastOrderAt: DateTime
  """The name of the customer."""
  name: String!
  """How many orders the customer placed."""
  orderCount: Int!
  """
  The ID of the team member the customer is attributed to: the assigned rep, else the creator.
  """
  repId: String
  """The name of that team member."""
  repName: String
  """The status of the customer."""
  status: String!
  """The revenue from the customer."""
  totalRevenue: Float!
}

"""A page of customers."""
type HierarchyCustomerPage {
  """True when there are more pages."""
  hasNextPage: Boolean!
  """The customers on this page."""
  items: [HierarchyCustomer!]!
  """The page number."""
  page: Int!
  """How many rows per page."""
  pageSize: Int!
  """How many match in all."""
  totalCount: Int!
}

"""Which customers of a node to list, one page at a time."""
input HierarchyCustomersInput {
  """Only figures from this date."""
  dateFrom: DateTime
  """Only figures up to this date."""
  dateTo: DateTime
  """The page number."""
  page: Int = 1
  """How many rows per page."""
  pageSize: Int = 20
  """Only customers attributed to this team member."""
  repId: String!
  "Text to search for."
  search: String
  """Only customers in this status."""
  status: String
}

"""
Headline figures for one selected node, counting the node and everyone below it.
"""
type HierarchyNodeSummary {
  """How many customers the node and its team have."""
  customerCount: Int!
  """How many people below the node there are in each role."""
  descendantsByRole: [HierarchyRoleCount!]!
  """How many people report directly to the node."""
  directReports: Int!
  """The name of the node."""
  name: String!
  """How many orders the node and its team have."""
  orderCount: Int!
  """
  True when the node sees the whole organization, not just the people below it.
  """
  orgWide: Boolean!
  """The node's own share of the customer count."""
  ownCustomerCount: Int!
  """The node's own share of the order count."""
  ownOrderCount: Int!
  """The node's own share of the revenue."""
  ownRevenue: Float!
  """The role of the node."""
  role: String
  """How many people are below the node."""
  teamSize: Int!
  """The revenue of the node and its team."""
  totalRevenue: Float!
  "The ID of the user."
  userId: ID!
}

"""One order of a customer in the drill-down."""
type HierarchyOrder {
  "The unique ID of this record."
  id: ID!
  """How many lines the order has."""
  itemCount: Int!
  """The currency of the order."""
  orderCurrency: String!
  """The date of the order."""
  orderDate: DateTime!
  """The order number."""
  orderNumber: String!
  """The payment status of the order."""
  paymentStatus: String!
  """The status of the order."""
  status: String!
  """The order amount before tax."""
  subtotal: Float!
  """The tax on the order."""
  taxAmount: Float!
  """The order total including tax."""
  totalAmount: Float!
}

"""A page of orders."""
type HierarchyOrderPage {
  """True when there are more pages."""
  hasNextPage: Boolean!
  """The orders on this page."""
  items: [HierarchyOrder!]!
  """The page number."""
  page: Int!
  """How many rows per page."""
  pageSize: Int!
  """How many match in all."""
  totalCount: Int!
}

"""Which orders to list, one page at a time."""
input HierarchyOrdersInput {
  "The ID of the customer."
  customerId: String!
  """Only orders on or after this date."""
  dateFrom: DateTime
  """Only orders on or before this date."""
  dateTo: DateTime
  """Only orders of at most this amount."""
  maxAmount: Float
  """Only orders of at least this amount."""
  minAmount: Float
  """The page number."""
  page: Int = 1
  """How many rows per page."""
  pageSize: Int = 20
  """Only orders of customers attributed to this team member."""
  repId: String!
  """Only orders in this status."""
  status: String
}

"""How many people have one role."""
type HierarchyRoleCount {
  """How many people."""
  count: Int!
  """The role."""
  role: String!
}

"""One top-level role tab, for example Manager, Sub Admin or Sales Rep."""
type HierarchyRoleTab {
  """The role shown on the tab."""
  role: String!
  """How many users have the role."""
  userCount: Int!
}

"""
One user row in the hierarchy browser. The counts and revenue include the user and everyone who reports to them, directly or not.
"""
type HierarchyUser {
  """The URL of the user's picture."""
  avatar: String
  """How many customers the user and their team have."""
  customerCount: Int!
  """How many people report directly to the user."""
  directReports: Int!
  "Email address."
  email: String!
  """The user's first name."""
  firstName: String!
  """When the user last signed in."""
  lastLogin: DateTime
  """The user's last name."""
  lastName: String!
  """The older role value, kept for older mutations."""
  legacyRole: String
  """The ID of the user's manager."""
  managerId: String
  """The name of the user's manager."""
  managerName: String
  """The user's name."""
  name: String!
  """How many orders the user and their team have."""
  orderCount: Int!
  """
  True when the counts cover the whole organization, not just the people below the user.
  """
  orgWide: Boolean!
  """The user's own share of the customer count."""
  ownCustomerCount: Int!
  """The user's own share of the order count."""
  ownOrderCount: Int!
  """The user's own share of the revenue."""
  ownRevenue: Float!
  "Phone number."
  phone: String
  """The user's role."""
  role: String
  "The ID of the role."
  roleId: String
  """The status of the user."""
  status: String!
  """How many people are below the user in all, not counting the user."""
  teamSize: Int!
  """The revenue of the user and their team."""
  totalRevenue: Float!
  "The ID of the user."
  userId: ID!
}

"""A page of users."""
type HierarchyUserPage {
  """True when there are more pages."""
  hasNextPage: Boolean!
  """The users on this page."""
  items: [HierarchyUser!]!
  """The page number."""
  page: Int!
  """How many rows per page."""
  pageSize: Int!
  """How many match in all."""
  totalCount: Int!
}

"""Which users to list, one page at a time."""
input HierarchyUsersInput {
  """List the direct reports of this manager instead of a role tab."""
  managerId: String
  """The page number."""
  page: Int = 1
  """How many rows per page."""
  pageSize: Int = 20
  """The role tab to list. Not with managerId."""
  role: String
  "Text to search for."
  search: String
  """Only users in this status."""
  status: String
  """
  With managerId, list the manager's indirect team: everyone below them except their direct reports.
  """
  team: Boolean = false
  """
  With managerId, list the organization's unplaced staff, who report to nobody. Only an organization-wide node has them.
  """
  unplaced: Boolean = false
}

"""A brand tile on the home screen."""
type HomeBrandCell {
  "The unique ID of this record."
  id: ID!
  """The URL of the brand logo."""
  logoUrl: String
  """The name of the brand."""
  name: String!
  """The code of the brand."""
  slug: String!
  """OkLCH or hex tile color used as fallback when logoUrl is missing."""
  tileColor: String
}

"""A brand logo on the home screen."""
type HomeBrandLogoCell {
  "The ID of the brand."
  brandId: ID
  """The URL of the brand logo."""
  logoUrl: String
  """The name of the brand."""
  name: String!
}

"""A category tile on the home screen."""
type HomeCategoryCell {
  "The unique ID of this record."
  id: ID!
  """The URL of the category image."""
  imageUrl: String
  """The name of the category."""
  name: String!
  """The code of the category."""
  slug: String!
  """OkLCH or hex tile color used as fallback when imageUrl is missing."""
  tileColor: String
}

"""The sections of the home screen, in order."""
type HomeFeed {
  """The sections."""
  sections: [HomeSection!]!
}

"""A promotion tile on the home screen."""
type HomePromoCell {
  """Internal route path or null for no-op."""
  href: String
  "The unique ID of this record."
  id: ID!
  """The URL of the promotion image."""
  imageUrl: String
  """The subtitle of the promotion."""
  subtitle: String
  """The title of the promotion."""
  title: String!
}

"""A quick link on the home screen."""
type HomeQuickLinkCell {
  """Internal route path, e.g. /(tabs)/shop/clp/dairy"""
  href: String!
  """The key of the icon."""
  iconKey: String!
  """The text of the link."""
  label: String!
}

"""One section of the buyer app home screen. The kind field tells which."""
union HomeSection = BrandPremixSection | CategoryGridSection | FestiveBannerSection | HeroCarouselSection | InfoStripSection | MiniPromoRowSection | QuickLinksSection | SecondaryAdSection | ShopByBrandsSection | ShopByCategoriesSection | TrustedBrandsRailSection

"""The kind of a home section."""
enum HomeSectionKind {
  """A brand block."""
  BRAND_PREMIX
  """A grid of categories."""
  CATEGORY_GRID
  """A seasonal banner."""
  FESTIVE_BANNER
  """The large carousel at the top."""
  HERO_CAROUSEL
  """A strip of short information."""
  INFO_STRIP
  """A row of small promotions."""
  MINI_PROMO_ROW
  """A banner on a product list page."""
  PLP_BANNER
  """A row of shortcuts."""
  QUICK_LINKS
  """A banner on the search page."""
  SEARCH_BANNER
  """A second advertisement."""
  SECONDARY_AD
  """A block for shopping by brand."""
  SHOP_BY_BRANDS
  """A block for shopping by category."""
  SHOP_BY_CATEGORIES
  """A grid of store locations."""
  STORES_GRID
  """A row of trusted brands."""
  TRUSTED_BRANDS_RAIL
}

"""The result of starting to find images for variants."""
type ImageSourcingStartResult {
  """The ID of the proposal card for the images."""
  cardId: String!
  """How many variants had images found."""
  matched: Int!
  """How many variants had none."""
  unmatched: Int!
}

"""One invoice row that could not be imported, and why."""
type ImportError {
  """What was wrong with the row."""
  errors: [String!]!
  """The invoice number on that row."""
  invoiceNumber: String!
  """The row number in the import file."""
  row: Int!
}

"""Supported file formats for bulk import operations"""
enum ImportFormat {
  """A comma-separated values file."""
  CSV
  """An Excel workbook."""
  EXCEL
}

"""A saved mapping of a supplier file's columns to product fields."""
type ImportMappingProfile {
  "When the record was created."
  createdAt: DateTime!
  """Which source column header feeds each product field."""
  fieldMap: JSON!
  "The unique ID of this record."
  id: String!
  "Whether the record is active."
  isActive: Boolean!
  """The name of the profile."""
  name: String!
  """The supplier the profile is for."""
  supplierName: String
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A page of inbox threads."""
type InboxConnection {
  """The threads on this page, each with its cursor."""
  edges: [InboxThreadEdge!]!
  """Paging information for this page."""
  pageInfo: InboxPageInfo!
  """Total threads in the folder."""
  totalCount: Int!
}

"""A folder of the email inbox: INBOX, SENT or DRAFTS."""
enum InboxFolderType {
  """Unsent drafts."""
  DRAFTS
  """Received mail."""
  INBOX
  """Sent mail."""
  SENT
}

"""Paging information for an inbox page."""
type InboxPageInfo {
  """Cursor of the last thread on the page."""
  endCursor: String
  """Whether more threads follow this page."""
  hasNextPage: Boolean!
  """Whether threads precede this page."""
  hasPreviousPage: Boolean!
  """Cursor of the first thread on the page."""
  startCursor: String
}

"""
One conversation in the email inbox: all emails that share a subject and document.
"""
type InboxThread {
  """A short plain-text preview of the latest message."""
  bodyPreview: String
  "The unique ID of this record."
  id: ID!
  """When the latest message was sent or received."""
  lastMessageAt: DateTime!
  """Last sender email in thread"""
  lastSenderEmail: String
  """Display name of the latest sender."""
  lastSenderName: String
  """Latest status: SENT, DELIVERED, OPENED, CLICKED, REPLIED"""
  latestStatus: String!
  """Number of messages in the conversation."""
  messageCount: Int!
  """Addresses that took part in the conversation."""
  participants: [String!]!
  """The ID of the document the conversation relates to."""
  referenceId: String
  """Quote number or Sales Order number"""
  referenceNumber: String
  """Type of document the conversation relates to."""
  referenceType: EmailReferenceType!
  """Subject line of the conversation."""
  subject: String!
  """Number of unread messages."""
  unreadCount: Int!
}

"""A thread in an inbox page, with its cursor."""
type InboxThreadEdge {
  """Cursor to pass as `after` to continue from this thread."""
  cursor: String!
  """The thread."""
  node: InboxThread!
}

"""Filters and paging for the email inbox thread list."""
input InboxThreadsInput {
  """Cursor of the last thread of the previous page."""
  after: String
  """Number of threads to return, 1 to 100. Defaults to 20."""
  first: Int = 20
  """Folder to list. Defaults to INBOX."""
  folder: InboxFolderType = INBOX
  """Filter by document type"""
  referenceType: EmailReferenceType
  """Search in subject, body, or email addresses"""
  search: String
}

"""An industry to pick from."""
type IndustryOption {
  """The text to show."""
  label: String!
  """The value that is saved."""
  value: String!
}

"""
A static information banner at the top of the home screen, drawn as one image.
"""
type InfoStripSection {
  """Where the strip leads."""
  href: String
  """The URL of the strip image."""
  imageUrl: String
  """The kind of home section."""
  kind: HomeSectionKind!
  """The title of the strip."""
  title: String
}

"""An image saved for a product."""
type IngestedImage {
  """Hosted image URL stored under the org prefix (drop into imageUrls)"""
  url: String!
}

"""The inspection of a received return."""
input InspectionInput {
  """The result for each line."""
  items: [InspectionItemInput!]!
  """The overall result of the inspection."""
  overallResult: OverallResult!
}

"""The inspection result for one return line."""
input InspectionItemInput {
  """The quantity accepted."""
  acceptedQuantity: Int!
  """The defects found."""
  defects: [String!]
  """What to do with the item."""
  inspectionResult: InspectionResult!
  """The ID of the return line."""
  itemId: String!
  """Notes about the inspection."""
  notes: String
  """The quality score given to the item."""
  qualityScore: Int!
  """The quantity rejected."""
  rejectedQuantity: Int!
  """The quantity sent for repair."""
  repairQuantity: Int!
  """The quantity that goes back into inventory."""
  restockQuantity: Int!
  """The quantity scrapped."""
  scrapQuantity: Int!
}

"""What to do with a returned item after inspection."""
enum InspectionResult {
  """Given away."""
  DONATE
  """Recycled."""
  RECYCLE
  """Can be repaired."""
  REPAIRABLE
  """Can be sold again."""
  RESELLABLE
  """Sent back to the supplier."""
  RETURN_TO_VENDOR
  """Thrown away."""
  SCRAP
}

"""Supported third-party integration services"""
enum IntegrationService {
  """Amazon."""
  AMAZON
  """Amazon S3 storage."""
  AWS_S3
  """Cloudinary image hosting."""
  CLOUDINARY
  """A custom integration."""
  CUSTOM
  """eBay."""
  EBAY
  """Google Analytics."""
  GOOGLE_ANALYTICS
  """Magento."""
  MAGENTO
  """Mailchimp."""
  MAILCHIMP
  """PayPal."""
  PAYPAL
  """QuickBooks."""
  QUICKBOOKS
  """SendGrid."""
  SENDGRID
  """Shopify."""
  SHOPIFY
  """Slack."""
  SLACK
  """Stripe."""
  STRIPE
  """Microsoft Teams."""
  TEAMS
  """A generic webhook."""
  WEBHOOK
  """WooCommerce."""
  WOOCOMMERCE
  """Xero."""
  XERO
  """Zoho Books."""
  ZOHO_BOOKS
}

"""An integration setting."""
type IntegrationSetting {
  """The integration's configuration, as JSON."""
  config: JSON!
  "When the record was created."
  createdAt: DateTime!
  """What the integration is for."""
  description: String
  """The name to show for the integration."""
  displayName: String!
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """True when the integration is switched on."""
  isEnabled: Boolean!
  """True when the last validation passed."""
  isValid: Boolean!
  """When the integration was last validated."""
  lastValidatedAt: DateTime
  "The ID of the organization the record belongs to."
  organizationId: String!
  """Which integration wins when several do the same job."""
  priority: Int!
  """The service the integration is for."""
  serviceName: IntegrationService!
  """Tags on the integration."""
  tags: [String!]!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """Why validation failed."""
  validationError: String
  """The version of the integration."""
  version: String!
  """The webhook address of the integration."""
  webhookUrl: String
}

"""Where one integration stands."""
type IntegrationStatus {
  """Why validation failed."""
  errorMessage: String
  """True when the integration is switched on."""
  isEnabled: Boolean!
  """True when the last validation passed."""
  isValid: Boolean!
  """When it was last validated."""
  lastValidated: DateTime
  """The service."""
  service: IntegrationService!
  """The status."""
  status: String
}

"""Headline integration figures."""
type IntegrationSummary {
  """How many are switched on."""
  enabledIntegrations: Int!
  """When the figures were worked out."""
  lastUpdated: DateTime!
  """The status of each integration."""
  statuses: [IntegrationStatus!]!
  """How many integrations there are."""
  totalIntegrations: Int!
  """How many passed validation."""
  validIntegrations: Int!
}

"""One line of an internal return between warehouses."""
input InternalReturnItemInput {
  """The condition the item is in."""
  condition: String!
  "The ID of the product."
  productId: String!
  """The quantity returned. Must be greater than zero."""
  quantity: Int!
  "The ID of the product variant."
  variantId: String!
}

"""The stock of one product variant in one warehouse."""
type Inventory {
  """The quantity free to allocate."""
  availableQuantity: Float!
  """The average cost of one unit."""
  averageCost: Float!
  """The batch number of the stock."""
  batchNumber: String
  "When the record was created."
  createdAt: DateTime!
  """
  The low stock threshold in force for the row: its own reorder point or minimum, else the organization's setting. 0 means none is set, so the row is never low.
  """
  effectiveReorderPoint: Float
  """The date the stock expires."""
  expiryDate: DateTime
  "The unique ID of this record."
  id: ID!
  """The quantity on order and not yet received."""
  incomingQuantity: Float!
  """When the stock was last counted."""
  lastCountedAt: DateTime
  """The quantity found at the last count."""
  lastCountedQty: Float
  """The most recent stock movement on the row."""
  lastMovement: StockMovement
  """The days it takes to replenish the stock."""
  leadTimeDays: Float!
  """The highest quantity the row should hold."""
  maximumQuantity: Float
  """The lowest quantity the row should hold."""
  minimumQuantity: Float!
  """The product."""
  product: Product!
  """The quantity on hand, reservations included."""
  quantity: Float!
  """The quantity at which the row counts as low stock."""
  reorderPoint: Float!
  """
  How much to buy when the reorder point is reached. Advisory, nothing orders by itself.
  """
  reorderQuantity: Float!
  """The quantity held by confirmed orders."""
  reservedQuantity: Float!
  """The serial number of the stock."""
  serialNumber: String
  """
  The stock status worked out on the server: OUT_OF_STOCK, LOW_STOCK, OVERSTOCK or IN_STOCK.
  """
  stockLevel: String
  """The value of the stock."""
  totalValue: Float!
  """The unit of measure the stock is kept in."""
  uom: UnitOfMeasure!
  "When the record was last changed."
  updatedAt: DateTime!
  """What the stock is worth."""
  valuation: InventoryValuation
  """The product variant."""
  variant: ProductVariant
  """The warehouse holding the stock."""
  warehouse: Warehouse!
}

"""Stock figures."""
type InventoryAnalytics {
  """How many items are overstocked."""
  excessStockItems: Int!
  """How many times stock turned over."""
  inventoryTurnover: Float!
  """How many items are low on stock."""
  lowStockItems: Int!
  """The products that are low on stock."""
  lowStockProducts: [InventoryProduct!]!
  """How many items are out of stock."""
  outOfStockItems: Int!
  """The stock of each category."""
  stockByCategory: [CategoryStock!]!
  """The products that move fastest."""
  topMovingProducts: [InventoryProduct!]!
  """How many products are stocked."""
  totalProducts: Int!
  """The value of the stock."""
  totalValue: Float!
  """How full each warehouse is."""
  warehouseUtilization: [WarehouseUtilization!]!
}

"""Stock figures for the period."""
type InventoryAnalyticsV2 {
  """Stock that has not moved for a long time."""
  deadStock: [DeadStockItem!]!
  """Batches close to expiring."""
  expiringBatches: [ExpiringBatch!]!
  """Stock movements split by type."""
  movementMix: [MovementSlice!]!
  """How many products were sold beyond the stock."""
  oversold: Int!
  """Stock lost to negative adjustments."""
  shrinkage: ShrinkageSummary!
  """How many products ran out of stock."""
  stockouts: Int!
  """How many times stock turned over."""
  turnoverRatio: Float!
  """The value of stock in each warehouse."""
  valuation: [WarehouseValuation!]!
}

"""Filters for the stock list."""
input InventoryFilterInput {
  """Only stock in this batch."""
  batchNumber: String
  """Only rows created on or after this date."""
  createdAtFrom: String
  """Only rows created on or before this date."""
  createdAtTo: String
  """Only rows that are in stock."""
  inStock: Boolean
  """Only rows that are low on stock."""
  lowStock: Boolean
  """Only rows holding at most this quantity."""
  maxQuantity: Float
  """Only rows holding at least this quantity."""
  minQuantity: Float
  """Only rows that are out of stock."""
  outOfStock: Boolean
  """Only rows that are overstocked."""
  overStock: Boolean
  "The ID of the product."
  productId: ID
  "Text to search for."
  search: String
  """Only stock with this serial number."""
  serialNumber: String
  """Only rows updated on or after this date."""
  updatedAtFrom: String
  """Only rows updated on or before this date."""
  updatedAtTo: String
  "The ID of the product variant."
  variantId: ID
  "The ID of the warehouse."
  warehouseId: ID
}

"""How to sort the stock list. Give one column."""
input InventoryOrderByInput {
  """Sort by quantity available."""
  availableQuantity: SortOrder
  """Sort by when the stock was last counted."""
  lastCountedAt: SortOrder
  """Sort by product name."""
  productName: SortOrder
  """Sort by quantity on hand."""
  quantity: SortOrder
  """Sort by quantity reserved."""
  reservedQuantity: SortOrder
  """Sort by stock value, which is the quantity times the cost."""
  totalValue: SortOrder
  """Sort by when the row was last updated."""
  updatedAt: SortOrder
  """Sort by variant name."""
  variantName: SortOrder
}

"""A product's stock position."""
type InventoryProduct {
  """The current stock."""
  currentStock: Int!
  """The lowest quantity the product should hold."""
  minStockLevel: Int
  "The ID of the product."
  productId: String!
  """The name of the product."""
  productName: String!
  """The quantity on hand."""
  quantity: Int
  """The quantity at which the product counts as low."""
  reorderPoint: Int
  """How fast the product turns over."""
  turnoverRate: Float
  """The variant's attributes, as JSON."""
  variantAttributes: JSON
  "The ID of the product variant."
  variantId: String
  """The name of the variant."""
  variantName: String
}

"""The period to work out stock figures for."""
input InventoryRangeInput {
  """The start of the period."""
  from: DateTime!
  """The end of the period."""
  to: DateTime!
  "The ID of the warehouse."
  warehouseId: ID
}

"""
One reservation behind a stock row's reserved quantity. It is made when a sales order is confirmed, used up when the order ships, and released on cancel or expiry.
"""
type InventoryReservationInfo {
  "When the record was created."
  createdAt: DateTime!
  """The customer on that order."""
  customerName: String
  """When the reservation expires."""
  expiresAt: DateTime!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The number of that order."""
  orderNumber: String
  """The status of that order."""
  orderStatus: String
  """The quantity reserved."""
  quantity: Float!
  """The ID of the sales order that holds the reservation."""
  reference: String!
  """When the reservation was released or used up."""
  releasedAt: DateTime
}

"""Inventory settings."""
input InventorySettingsInput {
  """True to allow stock to go below zero."""
  allowNegativeStock: Boolean
  """True to set reorder points automatically."""
  autoReorderPoint: Boolean
  """How stock is costed."""
  costingMethod: String
  """The ID of the organization's default unit of measure."""
  defaultUom: String
  """The ID of the default warehouse."""
  defaultWarehouse: String
  """True to track batches."""
  enableBatchTracking: Boolean
  """True to track expiry dates."""
  enableExpiryTracking: Boolean
  """True to link stock to production."""
  enableProductionIntegration: Boolean
  """True to link stock to purchases."""
  enablePurchaseIntegration: Boolean
  """True to link stock to sales."""
  enableSalesIntegration: Boolean
  """True to track serial numbers."""
  enableSerialTracking: Boolean
  """The quantity at or below which stock counts as low."""
  lowStockThreshold: String
}

"""Headline stock figures for the inventory dashboard."""
type InventorySummary {
  """How many stock rows are low."""
  lowStockItems: Int!
  """How many stock rows are out of stock."""
  outOfStockItems: Int!
  """How many stock rows are overstocked."""
  overstockItems: Int!
  """Recent stock movements grouped by type."""
  recentMovements: [RecentMovementSummary!]!
  """The total quantity free to allocate."""
  totalAvailable: Float!
  """How many products are stocked."""
  totalProducts: Int!
  """The total quantity on hand."""
  totalQuantity: Float!
  """The value of the stock."""
  totalValue: Float!
  """How many variants are stocked."""
  totalVariants: Int!
}

"""What the stock of one inventory row is worth."""
type InventoryValuation {
  """The average cost of one unit."""
  averageCost: Float!
  "ISO 4217 currency code."
  currency: String!
  """The total value of the stock."""
  totalValue: Float!
}

"""Invites a person to a customer account."""
input InviteCustomerUserInput {
  """
  May approve teammates' over-limit order requests. Forced true for CUSTOMER_ADMIN.
  """
  approvesOrders: Boolean
  """
  Addresses to assign to the new login. Meaningful only for CUSTOMER_BUYER / CUSTOMER_VIEWER — omit or [] leaves them with NO addresses until the owner assigns some (resolveAddressScope). A CUSTOMER_ADMIN invite is always unrestricted regardless of this field. Applied only to a genuinely new invite; an email already owned elsewhere returns the uniform anti-enumeration shape and assigns nothing.
  """
  assignedAddressIds: [ID!]
  "Email address."
  email: String!
  """The person's first name."""
  firstName: String
  """The person's last name."""
  lastName: String
  """
  Per-buyer order-value ceiling in the org base currency; null/omitted = no limit.
  """
  orderLimit: Float
  "The ID of the partner."
  partnerId: ID!
  """
  CUSTOMER_ADMIN | CUSTOMER_BUYER | CUSTOMER_VIEWER (default CUSTOMER_BUYER).
  """
  role: String
}

"""The result of inviting a person."""
type InviteCustomerUserResult {
  "Email address."
  email: String!
  """True when the invitation was sent."""
  invited: Boolean!
  "The ID of the user."
  userId: ID!
}

"""
A sales invoice issued to a customer or a purchase invoice received from a supplier, with its lines, totals, status and settlement.
"""
type Invoice {
  """The payment allocations applied to this invoice, including reversals."""
  allocations: [PaymentAllocation!]!
  """
  The outstanding amount in the organization's base currency. Null on older invoices.
  """
  baseOutstandingAmount: Float
  """
  The invoice total in the organization's base currency, frozen when the invoice was written. Null on older invoices.
  """
  baseTotalAmount: Float
  """The billing address on the invoice."""
  billingAddress: JSON
  """When the record was created."""
  createdAt: DateTime!
  """Currency code of the document's amounts."""
  currency: String
  """When the record was deleted. Null while it is active."""
  deletedAt: DateTime
  """Total discount amount on the invoice."""
  discountAmount: Float!
  """
  One label for display: CANCELLED, VOIDED, PAID, OVERDUE, PARTIALLY_PAID, DRAFT, SENT or AWAITING_PAYMENT.
  """
  displayStatus: String!
  """The date payment is due."""
  dueDate: DateTime!
  """The ID of the user who created the record."""
  enteredBy: String!
  """
  Exchange rate between the document currency and the organization's base currency, when they differ.
  """
  exchangeRate: Float
  """Unique identifier of the record."""
  id: ID!
  """Notes for your team only; never shown to the customer."""
  internalNotes: String
  """The date the invoice was issued."""
  invoiceDate: DateTime!
  """The human-readable invoice number, unique within the organization."""
  invoiceNumber: String!
  """
  True when the invoice has been issued (not a draft, cancelled or voided), still has an amount outstanding and is past its due date.
  """
  isOverdue: Boolean!
  """The line items on the invoice."""
  items: [InvoiceItem!]
  """Notes on the document, visible to the customer."""
  notes: String
  """The sales order this invoice bills, if any."""
  order: SalesOrder
  """
  Money already received or claimed for the order this invoice came from that no invoice has absorbed yet. While it is above zero the invoice shows the full amount unpaid and a new payment would pay the order twice. Null when there is none.
  """
  orderAdvance: InvoiceOrderAdvance
  """
  The ID of the sales order (sales invoice) or purchase order (purchase invoice) this invoice bills.
  """
  orderId: ID
  """The ID of the organization (tenant) that owns the record."""
  organizationId: String!
  """The amount still unpaid, in the invoice currency."""
  outstandingAmount: Float!
  """The amount paid so far, in the invoice currency."""
  paidAmount: Float!
  """The customer or supplier on the invoice."""
  partner: Partner
  """The ID of the customer (sales invoice) or supplier (purchase invoice)."""
  partnerId: String!
  """
  How much of the invoice has been paid: UNPAID, PARTIALLY_PAID or PAID, derived from paidAmount and totalAmount.
  """
  paymentStatus: String!
  """The payment terms agreed for the invoice."""
  paymentTerms: String
  """The ID of the purchase order this invoice bills, if any."""
  purchaseOrderId: String
  """The sales order this invoice bills, if any."""
  salesOrder: SalesOrder
  """The ID of the sales order this invoice bills, if any."""
  salesOrderId: String
  """The shipping address on the invoice."""
  shippingAddress: JSON
  """Shipping charge on the invoice."""
  shippingAmount: Float!
  """
  Where the invoice is in its lifecycle: DRAFT, APPROVED, PENDING, SENT, CANCELLED or VOIDED.
  """
  status: InvoiceStatus!
  """Subtotal of the invoice lines, as calculated by the server."""
  subtotal: Float!
  """The supplier's code, on a purchase invoice."""
  supplierCode: String
  """The supplier's display name, on a purchase invoice."""
  supplierDisplayName: String
  """The supplier's email address, on a purchase invoice."""
  supplierEmail: String
  """The supplier's name, on a purchase invoice."""
  supplierName: String
  """The supplier's phone number, on a purchase invoice."""
  supplierPhone: String
  """Surcharge added to the invoice."""
  surchargeAmount: Float!
  """Total tax on the invoice."""
  taxAmount: Float!
  """
  Whether line prices include tax (INCLUSIVE) or tax is added on top (EXCLUSIVE).
  """
  taxCalculationMethod: String
  """Terms and conditions printed on the invoice."""
  terms: String
  """
  The invoice total in the invoice currency, as calculated and stored by the server.
  """
  totalAmount: Float!
  """
  SALES_INVOICE for an invoice you issue to a customer, PURCHASE_INVOICE for a bill you receive from a supplier.
  """
  type: InvoiceType!
  """When the record was last changed."""
  updatedAt: DateTime!
  """The ID of the user who last changed the record."""
  updatedBy: String!
  """
  Optimistic-concurrency counter — pass back as expectedVersion on the next mutation.
  """
  version: Int!
}

"""A payment allocation on the invoice that the cancellation reverses."""
type InvoiceCancellationAllocationPreview {
  """The amount allocated from the payment to the invoice."""
  amount: Float!
  "The unique ID of this record."
  id: ID!
  "The ID of the payment."
  paymentId: ID!
  """The number of the payment."""
  paymentNumber: String
}

"""
The commission rows on the order that cancelling the invoice affects, and whether any needs a manual clawback.
"""
type InvoiceCancellationCommissionImpactPreview {
  """How many commission rows on the order the cancellation affects."""
  affectedCommissionRowCount: Int!
  """The commission amount that is already locked or paid."""
  lockedOrPaidAmount: Float!
  """
  True when locked or paid commission means someone must claw it back by hand.
  """
  requiresManualClawback: Boolean!
  "The ID of the sales order."
  salesOrderId: ID
}

"""
A credit note whose application on the invoice is given back by the cancellation: reopened (raised on another invoice) or cancelled (raised on this one).
"""
type InvoiceCancellationCreditNotePreview {
  """How much of the credit note is applied to this invoice."""
  amount: Float!
  "The ID of the credit note."
  creditNoteId: ID!
  """The number of the credit note."""
  creditNoteNumber: String!
}

"""
A credit note raised on this invoice that the customer already used on other invoices. Its amount comes off the money the cancellation gives back.
"""
type InvoiceCancellationCreditUsedElsewherePreview {
  """How much of the credit note was used on other invoices."""
  amount: Float!
  "The ID of the credit note."
  creditNoteId: ID!
  """The number of the credit note."""
  creditNoteNumber: String!
  """The numbers of the other invoices that used the credit note."""
  usedOnInvoiceNumbers: [String!]!
}

"""An order line whose invoiced quantity the cancellation restores."""
type InvoiceCancellationLineRestorePreview {
  """The quantity of the line that is invoiced now."""
  currentInvoicedQuantity: Float!
  "The ID of the product."
  productId: ID
  """The quantity that returns to uninvoiced when the invoice is cancelled."""
  quantityToRestore: Float!
  """The ID of the order line."""
  salesOrderItemId: ID!
}

"""
A side-effect-free preview of cancelling an invoice: whether it can be cancelled, what blocks it, and the payments, credit notes, stock and commission effects.
"""
type InvoiceCancellationPreview {
  """The payment allocations the cancellation reverses."""
  allocations: [InvoiceCancellationAllocationPreview!]!
  """Reasons the invoice cannot be cancelled. Empty when it can."""
  blockers: [String!]!
  """False when blockers is not empty."""
  canCancel: Boolean!
  """
  Credit notes raised on this invoice and applied only to it, which are cancelled with it.
  """
  cancelledCreditNotes: [InvoiceCancellationCreditNotePreview!]!
  """The effect on commission for the order. Null when none."""
  commissionImpact: InvoiceCancellationCommissionImpactPreview
  """
  Credit from this invoice that was already used on other invoices and is netted off.
  """
  creditUsedElsewhere: [InvoiceCancellationCreditUsedElsewherePreview!]!
  """The total of creditUsedElsewhere. Null for a purchase invoice."""
  creditUsedElsewhereAmount: Float
  """The status of the order now."""
  currentOrderStatus: String
  """The status of the invoice now."""
  currentStatus: String!
  """
  The amount of the credit note the cancellation issues for cash paid, less credit already used on other invoices. Null when nothing is given back.
  """
  estimatedCreditNoteAmount: Float
  """
  The amount of the debit note the cancellation issues. Null when none is issued.
  """
  estimatedDebitNoteAmount: Float
  "The ID of the invoice."
  invoiceId: ID!
  """The number of the invoice."""
  invoiceNumber: String!
  """The order lines whose invoiced quantity is restored."""
  lineRestorations: [InvoiceCancellationLineRestorePreview!]!
  """The ID of the order the invoice was raised from."""
  orderId: ID
  """The number of that order."""
  orderNumber: String
  """The cash paid on this sales invoice. Null for a purchase invoice."""
  paidOnInvoiceAmount: Float
  """
  The status the order moves to once the invoiced quantities are restored.
  """
  projectedOrderStatus: String
  """
  Credit notes raised on another invoice whose application to this invoice is reopened.
  """
  reopenedCreditNotes: [InvoiceCancellationCreditNotePreview!]!
  """
  True when money is settled on the invoice, through payments or applied credit notes. Pass reverseAllocations: true to cancel.
  """
  requiresReverseAllocationsFlag: Boolean!
  """
  The completed stock movements from this invoice that the cancellation reverses.
  """
  stockMovements: [InvoiceCancellationStockMovementPreview!]!
  """The total of those allocations."""
  totalAllocatedAmount: Float!
}

"""A stock movement linked to the invoice that the cancellation affects."""
type InvoiceCancellationStockMovementPreview {
  """The ID of the warehouse the stock leaves, if any."""
  fromWarehouseId: ID
  "The unique ID of this record."
  id: ID!
  """The number of the stock movement."""
  movementNumber: String!
  """The quantity moved."""
  quantity: Float!
  """The ID of the warehouse the stock goes to, if any."""
  toWarehouseId: ID
  """The type of the stock movement."""
  type: String!
}

"""A page of invoices and the total number that match."""
type InvoiceConnection {
  """The invoices on this page."""
  invoices: [Invoice!]!
  """How many invoices match the filter in all."""
  total: Int!
}

"""
How much of a sales invoice has been credited and how much is left to credit.
"""
type InvoiceCreditHeadroom {
  """How much of the invoice has already been credited."""
  alreadyCredited: Float!
  """How many credit notes count against the invoice."""
  creditNoteCount: Int!
  "ISO 4217 currency code."
  currency: String!
  "The ID of the invoice."
  invoiceId: ID!
  """The number of the invoice."""
  invoiceNumber: String!
  """The status of the invoice."""
  invoiceStatus: String!
  """The invoice total, in the invoice currency."""
  invoiceTotal: Float!
  """How much of the invoice can still be credited."""
  remaining: Float!
}

"""
How much of a purchase invoice has been debited and how much is left to debit.
"""
type InvoiceDebitHeadroom {
  """How much of the invoice has already been debited."""
  alreadyDebited: Float!
  "ISO 4217 currency code."
  currency: String!
  """How many debit notes count against the invoice."""
  debitNoteCount: Int!
  "The ID of the invoice."
  invoiceId: ID!
  """The number of the purchase invoice."""
  invoiceNumber: String!
  """The status of the invoice."""
  invoiceStatus: String!
  """The invoice total, in the invoice currency."""
  invoiceTotal: Float!
  """How much of the invoice can still be debited."""
  remaining: Float!
}

"""
The status an invoice list shows. PAID, PARTIALLY_PAID and OVERDUE are worked out from the amounts and the due date and are never stored; the rest are the stored statuses.
"""
enum InvoiceDisplayStatus {
  """Marked as approved."""
  APPROVED
  """Cancelled. A final status."""
  CANCELLED
  """Not yet issued."""
  DRAFT
  """Past its due date with an amount still outstanding."""
  OVERDUE
  """Fully paid."""
  PAID
  """Some of the total has been paid and some is still outstanding."""
  PARTIALLY_PAID
  """The starting status of a newly created invoice."""
  PENDING
  """Sent to the customer or supplier."""
  SENT
  """Voided. A final status."""
  VOIDED
}

"""Filters and sorting for the invoice list."""
input InvoiceFilterInput {
  """
  Only invoices whose displayed status matches. PAID, PARTIALLY_PAID and OVERDUE are worked out from the amounts and due date, not stored. Use this or status, not both.
  """
  displayStatus: InvoiceDisplayStatus
  """Only invoices due strictly before this date."""
  dueBefore: String
  """Only invoices due on or after this date."""
  dueOnOrAfter: String
  """Only invoices dated on or before this ISO 8601 date."""
  endDate: String
  """Only invoices entered by this user."""
  enteredBy: String
  """
  When true, only invoices that still owe money: outstanding amount above zero and not DRAFT, CANCELLED or VOIDED.
  """
  hasOutstanding: Boolean
  """Only invoices for this customer or supplier."""
  partnerId: ID
  """Only invoices with this payment term code."""
  paymentTermsCode: String
  """Text to search for in invoices."""
  search: String
  """Field to sort by. Omitted means most recently updated first."""
  sortBy: InvoiceSortField
  """Sort direction."""
  sortOrder: SortOrder
  """Only invoices dated on or after this ISO 8601 date."""
  startDate: String
  """Only invoices with this stored status."""
  status: InvoiceStatus
  """Only invoices of this type: SALES_INVOICE or PURCHASE_INVOICE."""
  type: InvoiceType
  """
  Only invoices changed strictly after this instant. Used for incremental sync; it can only narrow what the caller may see.
  """
  updatedAfter: String
}

"""Supported file formats for invoice bulk import operations"""
enum InvoiceImportFormat {
  """A comma-separated values file."""
  CSV
  """An Excel workbook."""
  EXCEL
}

"""Types of invoices for bulk import operations"""
enum InvoiceImportType {
  """Import bills received from suppliers."""
  PURCHASE_INVOICE
  """Import invoices issued to customers."""
  SALES_INVOICE
}

"""A short reference to an invoice: its ID, number, date and status."""
type InvoiceInfo {
  "The unique ID of this record."
  id: ID!
  """Date of the invoice."""
  invoiceDate: DateTime!
  """The invoice's number."""
  invoiceNumber: String!
  """Status of the invoice."""
  status: String!
}

"""
One line on an invoice: the product or variant billed, quantity, price, tax and discount.
"""
type InvoiceItem {
  """
  Buyer consent: if this item becomes unavailable, may fulfillment ship a manually-picked substitute instead? Consent + visibility only.
  """
  acceptAlternativeIfUnavailable: Boolean!
  """How many base units one unit of the line's unit of measure equals."""
  conversionFactor: Float
  """Free-text description of the line."""
  description: String!
  """Total discount amount on the line."""
  discountAmount: Float!
  """The line discount as a percentage."""
  discountPercent: Float!
  """
  The ID of the goods receipt line this line bills, on a purchase invoice.
  """
  grnItemId: String
  """Unique identifier of the record."""
  id: ID!
  """The ID of the invoice this line belongs to."""
  invoiceId: String!
  """The product on this line."""
  product: Product
  """The ID of the product on this line."""
  productId: String!
  """Quantity invoiced, in the line's unit of measure."""
  quantity: Float!
  """
  The quantity a new sales return may still take for this line: invoiced less already returned, and never more than its sales order line has left (returns made against the order count too); never below zero. Only set when a single sales invoice is fetched.
  """
  returnableQuantity: Float
  """
  The quantity of this line no longer returnable because it is on live sales returns, through this invoice or through the sales order it was raised from, in the line's unit. Only set when a single sales invoice is fetched.
  """
  returnedQuantity: Float
  """The ID of the sales order line this line bills, on a sales invoice."""
  salesOrderItemId: String
  """Total tax on the line."""
  taxAmount: Float!
  """
  Tax applied to this line, as a list of { taxName, taxCode, taxType, rate, taxAmount }.
  """
  taxBreakdown: JSON
  """The ID of the tax group applied to this line."""
  taxGroupId: String
  """The tax rate applied to the line, as a percentage."""
  taxRate: Float!
  """The IDs of the tax rates applied to this line."""
  taxRateIds: String
  """The line total, as calculated and stored by the server."""
  totalAmount: Float!
  """Price per unit before the line discount."""
  unitPrice: Float!
  """The ID of the unit of measure the quantity is expressed in."""
  uomId: ID
  """Name of the unit of measure."""
  uomName: String
  """The product variant on this line."""
  variant: ProductVariant
  """The ID of the product variant on this line."""
  variantId: String
  """The ID of the warehouse this line relates to."""
  warehouseId: String
}

"""
A quantity invoiced on one sales order line, with the invoice it belongs to.
"""
type InvoiceItemInfo {
  "The unique ID of this record."
  id: ID!
  """The invoice the quantity was billed on."""
  invoice: InvoiceInfo!
  """Quantity billed on that invoice."""
  quantity: Float!
}

"""One line of a new invoice."""
input InvoiceItemInput {
  """
  Whether the buyer accepts a substitute if this item is unavailable. Taken from the linked sales order line when omitted.
  """
  acceptAlternativeIfUnavailable: Boolean
  """Batch number of the goods on this line."""
  batchNumber: String
  """How many stock units one invoiced unit is worth. Must not be negative."""
  conversionFactor: Float
  """Description shown on the invoice line."""
  description: String!
  """
  The line discount as an amount. When sent it is used instead of re-deriving the amount from discountPercent. Must not be negative.
  """
  discountAmount: Float
  """Line discount as a percentage, from 0 to 100."""
  discountPercent: Float
  """The ID of the goods receipt line this purchase invoice line bills."""
  grnItemId: ID
  """The ID of the product being invoiced."""
  productId: ID!
  """
  Quantity invoiced, in the unit given by uomId. Must be greater than zero.
  """
  quantity: Float!
  """
  The ID of the sales order line this invoice line bills. Keeps the link to the order and limits invoicing to the quantity not yet invoiced.
  """
  salesOrderItemId: ID
  """Serial number of the goods on this line."""
  serialNumber: String
  """Tax split by component, as JSON."""
  taxBreakdown: JSON
  """
  Tax rate for the line. When omitted or 0 the server resolves tax from the product's tax setup; a rate you send overrides it.
  """
  taxRate: Float
  """Price per unit. Must not be negative."""
  unitPrice: Float!
  """The ID of the unit of measure for the quantity."""
  uomId: ID
  """Name of the unit of measure, shown on the line."""
  uomName: String
  """The ID of the product variant being invoiced."""
  variantId: ID!
  """The ID of the warehouse the goods ship from."""
  warehouseId: ID
}

"""
Totals for the invoice list, counted over the whole filtered set in the organization's base currency.
"""
type InvoiceListSummary {
  """How many matching invoices are drafts."""
  draftCount: Int!
  """The amount still owed on issued invoices, in the base currency."""
  dueAmount: Float!
  """
  How many matching invoices are issued, meaning not draft, cancelled or voided.
  """
  issuedCount: Int!
  """The amount still owed on overdue invoices, in the base currency."""
  overdueAmount: Float!
  """How many issued invoices are past their due date."""
  overdueCount: Int!
  """The amount paid on issued invoices, in the base currency."""
  paidAmount: Float!
  """The total of issued invoices, in the organization's base currency."""
  totalAmount: Float!
  """How many invoices match the filter, drafts and cancelled included."""
  totalCount: Int!
}

"""
Money already tied to the order this invoice came from and not yet applied to an invoice. While it is above zero the invoice still shows the full amount unpaid, and a new payment would pay the order twice.
"""
type InvoiceOrderAdvance {
  """The invoice's currency; every amount is in it."""
  currency: String
  """Each payment still waiting to be applied."""
  payments: [InvoiceOrderAdvancePayment!]!
  """The total not yet applied to any invoice, in the invoice's currency."""
  unappliedAmount: Float!
}

"""
One payment tied to the sales order an invoice came from that has not been applied to an invoice yet.
"""
type InvoiceOrderAdvancePayment {
  """What is left of this payment that has not been applied to any invoice."""
  amount: Float!
  """The payment's id; opens its collection page."""
  paymentId: ID!
  """The collection number."""
  paymentNumber: String
  """
  DRAFT (the admin's own entry, confirm it first), AWAITING_ACCEPTANCE (the customer's transfer, accept it or void it) or CONFIRMED (money received, apply it to the invoice).
  """
  state: String!
}

"""Fields the invoice list can be sorted by."""
enum InvoiceSortField {
  """The payment due date."""
  DUE_DATE
  """The invoice date."""
  INVOICE_DATE
  """The amount still owed."""
  OUTSTANDING_AMOUNT
  """The invoice total."""
  TOTAL_AMOUNT
  """When the invoice was last changed."""
  UPDATED_AT
}

"""
The stored lifecycle status of an invoice. DRAFT, PENDING and APPROVED are independent flags before sending, with no required order; CANCELLED and VOIDED are final. Paid, partly paid and overdue are not stored; see InvoiceDisplayStatus.
"""
enum InvoiceStatus {
  """
  Marked as approved. It is a flag only: an invoice does not have to be approved before it is sent.
  """
  APPROVED
  """
  Cancelled with cancelInvoice. A final status: the invoice cannot change again.
  """
  CANCELLED
  """
  Not yet issued, such as a duplicated invoice that is still being prepared.
  """
  DRAFT
  """The starting status of a newly created invoice."""
  PENDING
  """Sent to the customer or supplier."""
  SENT
  """Voided. A final status: the invoice cannot change again."""
  VOIDED
}

"""Whether an invoice is a sales invoice or a purchase invoice."""
enum InvoiceType {
  """A bill you receive from a supplier."""
  PURCHASE_INVOICE
  """An invoice you issue to a customer."""
  SALES_INVOICE
}

"""The condition a returned item is in."""
enum ItemCondition {
  """Damaged in transit or handling."""
  DAMAGED
  """Faulty from manufacture."""
  DEFECTIVE
  """Past its expiry date."""
  EXPIRED
  """In good condition."""
  GOOD
}

"""
The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
"""
scalar JSON

"""A rep's plan for one day: the stops they will visit."""
type JourneyPlan {
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """Notes on the plan."""
  notes: String
  """The day of the plan."""
  planDate: DateTime!
  """The ID of the rep."""
  salesRepId: String!
  """The name of the rep."""
  salesRepName: String
  "When the record was last changed."
  updatedAt: DateTime!
  """The stops of the plan."""
  visits: [Visit!]!
}

"""Search, status and sorting for the journey plan list."""
input JourneyPlanListFilterInput {
  "Text to search for."
  search: String
  """The column to sort by. Defaults to plan date, earliest first."""
  sortBy: JourneyPlanSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only plans in this route status."""
  status: JourneyPlanRouteStatus
}

"""Totals of the route planning list, counted over the whole date range."""
type JourneyPlanListSummary {
  """How many of those stops are completed."""
  completedStops: Int!
  """How many day plans there are in the range, one per rep per day."""
  plans: Int!
  """How many stops those plans have."""
  stops: Int!
}

"""
A day plan's route status, worked out from its stops: NO_PLAN, PLANNED, IN_PROGRESS or COMPLETED.
"""
enum JourneyPlanRouteStatus {
  """All visits are done."""
  COMPLETED
  """The rep has started the route."""
  IN_PROGRESS
  """There is no plan for the day."""
  NO_PLAN
  """The route is planned and not started."""
  PLANNED
}

"""A column the journey plan list can be sorted by."""
enum JourneyPlanSortField {
  """The date of the plan."""
  PLAN_DATE
  """The sales rep."""
  SALES_REP
  """When the plan was last changed."""
  UPDATED_AT
}

"""One stop of a day plan."""
input JourneyPlanVisitInput {
  "The ID of the partner."
  partnerId: String!
  """The position of the stop in the day."""
  sequence: Int!
}

"""A language the product is available in."""
type Language {
  """The language code."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  """The writing direction."""
  direction: LanguageDirection!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """The name of the language."""
  name: String!
  """The name of the language in that language."""
  nativeName: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""Language text direction (LTR or RTL)"""
enum LanguageDirection {
  """Written left to right."""
  LTR
  """Written right to left."""
  RTL
}

"""The average days between stages of the purchasing cycle."""
type LeadTimes {
  """Days from bill to payment."""
  billToPaid: Float
  """Days from goods receipt to bill."""
  grnToBill: Float
  """Days from purchase order to goods receipt."""
  poToGrn: Float
  """Days from purchase order to payment."""
  total: Float!
}

"""How much revenue discounts gave away."""
type LeakageSummary {
  """The discount given by each rep."""
  byRep: [RepLeakage!]!
  """The discount as a percent of revenue plus discount."""
  leakagePct: Float!
  """The total discount given."""
  totalDiscount: Float!
}

"""A sellable UOM pack option for a product (P1d)."""
type LinePackOption {
  """Base units contained in one of this UOM (1 = base unit)."""
  conversionFactor: Float!
  """True when the pack can be bought."""
  isPurchase: Boolean!
  """True when the pack can be sold."""
  isSales: Boolean!
  """The list price of the pack."""
  listPrice: Float
  """The name of the pack."""
  name: String!
  """The sale price of the pack."""
  salePrice: Float
  """The symbol of the pack's unit."""
  symbol: String
  """
  This pack's own native qty-break ladder (per this UOM, no cf); null when it has none. Never synthesized from another UOM's ladder.
  """
  tierBreaks: [LineTierBreak!]
  "The ID of the unit of measure."
  uomId: String!
}

"""Order quantity rules for a sellable line (P1d)."""
type LineQtyRules {
  """The largest quantity that can be ordered."""
  maxOrderQuantity: Int
  """The smallest quantity that can be ordered."""
  minOrderQuantity: Int!
  """Quantity step; bulk entry snaps to this multiple."""
  orderMultiple: Int!
}

"""One tax component on a line (P1d)."""
type LineTaxBreakdownItem {
  """The rate, in percent."""
  rate: Float!
  """The tax."""
  taxAmount: Float!
  """The code of the tax."""
  taxCode: String
  """The name of the tax."""
  taxName: String!
}

"""Per-product tax resolved from the product tax config (P1d)."""
type LineTaxInfo {
  """Tax on the whole line (post-discount)."""
  amount: Float!
  """The tax of each rate on the line."""
  breakdown: [LineTaxBreakdownItem!]!
  """True when the line is exempt from tax."""
  exempt: Boolean!
  """True when tax is price-inclusive (extracted) vs added on top."""
  inclusive: Boolean!
  """Effective blended rate as a percentage of the taxable base."""
  rate: Float!
}

"""One qty-break tier (per selected UOM) (P1d)."""
type LineTierBreak {
  """The largest quantity the price applies to."""
  maxQuantity: Int
  """The smallest quantity the price applies to."""
  minQuantity: Int!
  """The price of one unit in the tier."""
  unitPrice: Float!
  """
  UOM the break qty/price are denominated in; null = base units (legacy ladder, ×cf).
  """
  uomId: String
}

"""The result of linking a guest's activity to a customer."""
type LinkGuestActivityResult {
  """
  How many guest rows of this browser are now linked to the signed-in customer.
  """
  linked: Int!
}

"""A reference to a purchase order linked to a sales order."""
type LinkedPurchaseOrderRef {
  """
  When the supplier is expected to deliver — answers 'when will this order's stock arrive?'.
  """
  expectedDate: DateTime
  "The unique ID of this record."
  id: ID!
  """The purchase order's number."""
  orderNumber: String!
  """Status of the purchase order."""
  status: String!
}

"""A reference to a sales order linked to a purchase order."""
type LinkedSalesOrderRef {
  "The unique ID of this record."
  id: ID!
  """The sales order's number."""
  orderNumber: String!
  """Status of the sales order."""
  status: String!
}

"""Signs a user in."""
input LoginInput {
  """A fingerprint of the device."""
  deviceFingerprint: String
  """A name for the device."""
  deviceName: String
  "Email address."
  email: String!
  """The password."""
  password: String!
  """True to keep the session longer."""
  rememberMe: Boolean
  """
  The subdomain of the organization. When left out, it is taken from the request host.
  """
  subdomain: String
  """True to skip two-factor on this device for a while."""
  trustDevice: Boolean
  """The two-factor code, when one is needed."""
  twoFactorToken: String
}

"""Signs a user in with a one-time code."""
input LoginWithOtpInput {
  """A fingerprint of the device."""
  deviceFingerprint: String
  """A name for the device."""
  deviceName: String
  "Email address."
  email: String!
  """The one-time code."""
  otp: String!
  """True to keep the session longer."""
  rememberMe: Boolean
  """The subdomain of the organization the code is for."""
  subdomain: String
  """True to skip two-factor on this device for a while."""
  trustDevice: Boolean
}

"""Where to upload a logo."""
type LogoUploadResponse {
  """The storage key of the file."""
  key: String!
  """The address the logo will be served from."""
  publicUrl: String!
  """The address to upload the file to."""
  uploadUrl: String!
}

"""
The gross margin over the period. It counts only revenue whose variant has a cost.
"""
type MarginSummary {
  """The margin of the top products."""
  byProductTop: [ProductMargin!]!
  """The cost of what was sold."""
  cost: Float!
  """
  The share of revenue where the variant has a cost. A low figure means the margin should be read with care.
  """
  coveragePct: Float!
  """The margin as a percent of the covered revenue."""
  marginPct: Float!
  """The revenue counted."""
  revenue: Float!
}

"""Marks a payout as paid."""
input MarkPayoutPaidInput {
  """The ID of the payout."""
  payoutId: String!
  """The payment reference."""
  reference: String
}

"""Marks a shipment's courier as paid."""
input MarkShipmentCourierPaidInput {
  """How it was paid, for example EFT, Card, Cash or Courier account."""
  method: String!
  """The date the courier was paid, as YYYY-MM-DD. Not in the future."""
  paidOn: String!
  """The bank or courier reference. Optional."""
  reference: String
}

"""Records one courier payment against many shipments at once."""
input MarkShipmentsCourierPaidInput {
  """How it was paid, for example EFT, Card, Cash or Courier account."""
  method: String!
  """The date the courier was paid, as YYYY-MM-DD. Not in the future."""
  paidOn: String!
  """The bank or courier reference. Optional."""
  reference: String
  """
  The shipments the payment settles, from 1 to 500. Each must still be owed and not yet marked paid.
  """
  shipmentIds: [ID!]!
}

"""What a batch of courier payments recorded."""
type MarkShipmentsCourierPaidResultGql {
  """How many shipments were marked paid."""
  markedCount: Int!
  """
  The courier charges settled, per currency. Currencies are never added together.
  """
  totals: [CourierPaymentBatchTotalGql!]!
  """
  How many shipments were booked before cost tracking. They are marked paid with no amount to add.
  """
  untrackedCount: Int!
}

"""A menu item."""
type Menu {
  """The child menu items."""
  children: [Menu!]
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the menu item is for."""
  description: String
  "The ID of the user who created the record."
  enteredBy: String!
  """The icon of the menu item."""
  icon: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """True when the item is a main menu entry."""
  isMainMenu: Boolean!
  """The text shown for the menu item."""
  label: String!
  """MAIN or SUB."""
  menuType: MenuType!
  """The internal name of the menu item."""
  name: String!
  """The position among its siblings, lowest first."""
  order: Int!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The parent menu item."""
  parent: Menu
  """The ID of the parent menu item."""
  parentId: String
  """The address the menu item opens."""
  path: String
  """The permissions needed to see the item."""
  requiredPermissions: [String!]
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""Filters for the menu list."""
input MenuFiltersInput {
  "Whether the record is active."
  isActive: Boolean
  """Only items of this type."""
  menuType: MenuType
  """Only the children of this item."""
  parentId: String
  "Text to search for."
  search: String
}

"""The type of menu item"""
enum MenuType {
  """A top-level menu."""
  MAIN
  """A submenu."""
  SUB
}

"""A home section showing a row of small promotions."""
type MiniPromoRowSection {
  """The kind of home section."""
  kind: HomeSectionKind!
  """The promotions."""
  promos: [HomePromoCell!]!
}

"""
Asks for an install handoff code before sending a phone to the app store. The code, never the invite token, travels with the store link.
"""
input MintInviteInstallHandoffInput {
  """
  Dev-only fallback subdomain. The request host (X-Original-Host → Host) always wins.
  """
  subdomain: String
  """The invite token from the /invite link's #fragment."""
  token: String!
}

"""One share of a revenue split."""
type MixSlice {
  "The unique ID of this record."
  id: ID!
  """The name of the category or brand."""
  name: String!
  """The revenue."""
  revenue: Float!
  """Its share of the total, in percent."""
  sharePct: Float!
}

"""Accepts an invitation to a buyer account."""
input MobileAcceptInviteInput {
  """
  OTP from the invited mailbox. Proof of LIVE mailbox control, so a FORWARDED invite link cannot be accepted by whoever holds it — verified server-side against the token's own email, never a client-supplied one.
  """
  code: String!
  """
  The person's first name. Optional, because the inviter already entered it.
  """
  firstName: String
  """The person's last name."""
  lastName: String
  """The subdomain of the organization."""
  subdomain: String
  """The invitation token."""
  token: String!
}

"""
Result of adding a partner-shared buying list to the MOBILE cart. Returns a summary, not a bare cart: a buyer who taps once must be told what was added and what was skipped, or they discover it at checkout.
"""
type MobileAddListToCartResult {
  """Lines merged onto the cart."""
  addedCount: Int!
  """The cart after the list was added."""
  cart: MobileCart!
  """Lines that could not be added, with the reason for each."""
  skipped: [MobileListSkip!]!
}

"""Adds an item to the cart."""
input MobileAddToCartInput {
  """A placeholder for the image while it loads."""
  blurhash: String
  """The URL of the product image."""
  imageUrl: String
  """A note on the line."""
  notes: String
  "The ID of the product."
  productId: ID!
  """The name of the product, for the cart display."""
  productName: String!
  """The quantity to add."""
  quantity: Int!
  """The unit of measure, for the cart display."""
  unitLabel: String
  """The price of one unit, for the cart display."""
  unitPrice: Float!
  """
  UOM the buyer selected on the PDP (each/case/carton). Optional; when omitted the server derives the variant sales/base UOM. Priced against this UOM and stored on the cart line so the same UOM flows to the SalesOrder (displayed == charged).
  """
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
  """The label of the variant, for the cart display."""
  variantLabel: String
}

"""An ordering address of the buyer."""
type MobileAddress {
  """The first line of the address."""
  addressLine1: String!
  """The second line of the address."""
  addressLine2: String
  """Address classification (AddressType enum)."""
  addressType: AddressType!
  """The city."""
  city: String!
  """The country."""
  country: String!
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """
  TRUE when this address also serves the OTHER role — a SHIPPING address that is billed to as well, or vice versa. `addressType` stays the primary classification (one enum column cannot hold two roles). Drives the cart/checkout heading: 'Shipping To' / 'Billing To' / 'Billing & Shipping'. Nullable for app builds that predate it.
  """
  isDualPurpose: Boolean
  """The latitude of the address on the map."""
  lat: Float
  """The longitude of the address on the map."""
  lng: Float
  """The name of the address."""
  name: String!
  "Phone number."
  phone: String!
  """The postal code."""
  postalCode: String
  """The state or region."""
  state: String
}

"""
Whether the buyer may add or edit addresses, and whether they are limited to assigned ones.
"""
type MobileAddressAccess {
  """
  How many addresses are assigned to this buyer. 0 when unscoped, which means unrestricted, NOT none.
  """
  assignedCount: Int!
  """
  FALSE when the account owner has assigned specific addresses to this buyer — the app hides its add/edit address controls. The server enforces the same rule regardless of what the app renders.
  """
  canAddAddress: Boolean!
  """
  TRUE when this buyer is confined to the addresses assigned to them. Read this rather than inferring from the length of `myAddresses`: one returned address does not mean the buyer is limited to one.
  """
  isScoped: Boolean!
}

"""The platform of a mobile app: IOS or ANDROID."""
enum MobileAppPlatform {
  """The Android app."""
  ANDROID
  """The iOS app."""
  IOS
}

"""
Public store listing links for one published app, BOTH platforms at once. Separate from mobileAppUpdateStatus, which answers a version question for the CALLING platform only — 'share this app' needs the other platform's link too, and 'rate this app' must work for a client that is already up to date (where the update query legitimately has nothing to say).
"""
type MobileAppStoreLinks {
  """
  The Play Store listing. Empty when no active Android release is set up.
  """
  androidUrl: String
  """The App Store listing. Empty when no active iOS release is set up."""
  iosUrl: String
}

"""
Where a mobile app stands: UP_TO_DATE, UPDATE_AVAILABLE for a dismissible prompt, or UPDATE_REQUIRED when it is below the supported floor and must update.
"""
enum MobileAppUpdateState {
  """A newer version exists; updating is optional."""
  UPDATE_AVAILABLE
  """The installed version is too old and must be updated."""
  UPDATE_REQUIRED
  """The installed version is current."""
  UP_TO_DATE
}

"""Whether the calling app needs updating."""
type MobileAppUpdateStatus {
  """The newest published version, when one is known."""
  latestVersion: String
  """What the newest version changes."""
  releaseNotes: String
  """Where the app stands against the published versions."""
  state: MobileAppUpdateState!
  """
  The store link to show on the update prompt. Empty when no release is configured.
  """
  storeUrl: String
}

"""
Several cart changes applied together, for example a bulk order confirm. Each line is checked and priced as a single change would be.
"""
input MobileApplyCartChangesInput {
  """The items to add."""
  adds: [MobileAddToCartInput!]! = []
  """The items to remove."""
  removes: [MobileRemoveCartItemInput!]! = []
  """The items to change."""
  updates: [MobileUpdateCartItemInput!]! = []
}

"""The result of a buyer sign in."""
type MobileAuthResponse {
  """The token to send with requests."""
  accessToken: String!
  """
  True if this is the first time the buyer has signed in (no address yet).
  """
  isNewBuyer: Boolean!
  """The token to get a new access token."""
  refreshToken: String!
  "The ID of the user."
  userId: ID!
}

"""
Authenticated buyer profile surface. v1 derives values from the JWT and Redis-backed addresses; promote to a Prisma-backed read model later.
"""
type MobileBuyerProfile {
  """
  Buyer account (customer) approval status: ACTIVE | PENDING_APPROVAL | INACTIVE. ACTIVE means the buyer may order; anything else drives the pending-approval banner and disables checkout.
  """
  accountStatus: String
  """How many addresses the buyer has."""
  addressCount: Int!
  """
  BUSINESS | INDIVIDUAL, read from the `Partner.type` COLUMN — the same field the seller console's customer form edits, so both surfaces always agree. Normalised: a legacy or role-shaped stored value reads as BUSINESS. Gates the buyer app's Team / Branches / Approvals flows, which exist only for a business account.
  """
  businessType: String
  """Company / business name (Partner.metadata)."""
  companyName: String
  """When the buyer first authenticated. Null until populated."""
  createdAt: DateTime
  """Department, read from the person's `Contact` rows."""
  department: String
  "Email address."
  email: String
  """The buyer's first name."""
  firstName: String
  "The unique ID of this record."
  id: ID!
  """The buyer's last name."""
  lastName: String
  """The buyer's full name."""
  name: String
  """
  Raw payment-terms code (Partner.paymentTerms, e.g. 'NET_30', 'COD') — the client formats it for display; this is the same code every document/pricing surface treats as canonical.
  """
  paymentTerms: String
  """E.164-formatted phone, +974 prefixed for Qatar."""
  phone: String
  """
  This buyer's own reference code (Contact.referenceId) — the same value the Team screen shows for each member. Null when they have no Contact row yet.
  """
  referenceId: String
  """Job title, read from the person's `Contact` rows."""
  title: String
  """
  E.164 WhatsApp number, read from the person's WHATSAPP `Contact` channel row — the only place one exists. Null when they have no WhatsApp row.
  """
  whatsapp: String
}

"""
Result of cancelPaymentCheckout: what happened to the abandoned checkout. `paid: true` means the PSP reported the session SUCCEEDED after all — the order was NOT cancelled and the client must route to the success screen.
"""
type MobileCancelCheckout {
  """True when this call moved the order to CANCELLED."""
  cancelled: Boolean!
  """The ID of the order."""
  orderId: ID!
  """The status of the order after the call."""
  orderStatus: String!
  """
  True when the payment turned out to be paid. A paid order is never cancelled by this call.
  """
  paid: Boolean!
}

"""
One shared cart per buyer (not per delivery address — the address is chosen at placeOrder). The same cart the customer portal reads and writes (one per branch in branch mode).
"""
type MobileCart {
  """
  Deprecated: always an empty string. The cart is no longer address-scoped; kept only to avoid a breaking schema field removal.
  """
  addressId: ID!
  """Free-text delivery instructions, max 200 chars."""
  directions: String
  "The unique ID of this record."
  id: ID!
  """
  Sum of the line quantities (fractional when a line is a fractional weight/volume pack).
  """
  itemCount: Float!
  """The items in the cart."""
  items: [MobileCartItem!]!
  """The cart amount before tax and delivery."""
  subtotal: Float!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""Itemised bill snapshot for the cart. v1 applies 5% Qatar VAT."""
type MobileCartBill {
  """True when the cart is below the seller's minimum order value."""
  belowMov: Boolean!
  """The ID of the cart."""
  cartId: ID!
  """Buyer's effective CUSTOMER/LOYALTY tier key (e.g. GOLD)."""
  customerTier: String
  """
  Delivery fee charged (0 when waived). Null only when `deliverySelectionRequired` — the store prices delivery live and no option is chosen yet; `total` then excludes delivery.
  """
  deliveryFee: Float
  """the live delivery option this bill's fee came from."""
  deliveryOptionId: ID
  """
  Box packing: true when the order is too heavy to price delivery live (mobileDeliveryOptions code DELIVERY_FREIGHT_QUOTE) — it is placed with no delivery charge (deliveryFee 0) and the store quotes delivery afterwards. Show "Delivery quoted after ordering".
  """
  deliveryQuoteRequired: Boolean!
  """
  true when the store prices delivery live and the buyer has not chosen a delivery option (mobileDeliveryOptions). Pass the option as deliveryOptionId on mobileCartBill and on placement.
  """
  deliverySelectionRequired: Boolean!
  """
  Total discount separating `grossSubtotal` from the net. On the CART path it is SUMMED from the per-line `lineDiscount` figures, exactly as the customer portal builds the same row — so `grossSubtotal - discountAmount` can sit one minor unit away from `subtotal` on a half-cent line (833.50 - 375.08 = 458.42 against a true net of 458.43). It was previously back-derived as `grossSubtotal - subtotal`, which made the rows reconcile on screen but reported a discount a cent away from the portal's for the same cart. On the placed-order path it is the order row's own `discountAmount`. 0 when nothing is discounted. Not the same as `tierDiscountAmount`/`quantityTierDiscountAmount`, which are attribution buckets WITHIN this figure.
  """
  discountAmount: Float!
  """
  GROSS pre-discount total (Σ per-line round(referencePrice × qty)). The bill's 'Item total' row. Read this — never reconstruct it client-side as `subtotal + savings`, which sums a ROUNDED per-unit saving and drifts by cents at quantity (buyer-app showed 833.45 instead of 833.50 on a 33.34 × 25 line). Mirrors the customer-portal bill's field of the same name (BUG-20260818).
  """
  grossSubtotal: Float!
  """Minimum order value in QAR."""
  mov: Float!
  """
  Always 0. The printed-invoice fee was removed until it has a configured source; kept so existing app builds that select it keep working.
  """
  printedInvoiceFee: Float!
  """
  Always 0. The printed-invoice fee was removed until it has a configured source; kept so existing app builds that select it keep working.
  """
  printedInvoiceFeeAmount: Float!
  """
  Always false. The printed-invoice fee was removed; kept so existing app builds that select it keep working.
  """
  printedInvoiceIncluded: Boolean!
  """
  Total QUANTITY/bulk-order pricing-tier savings across the cart (sum of each line's quantityTierUnitDiscount × quantity) — independent of tierDiscountAmount above.
  """
  quantityTierDiscountAmount: Float
  """
  CART path: the NET taxable amount — the post-discount sum of the cart's lines, where `grossSubtotal - discountAmount === subtotal` holds exactly. PLACED-ORDER path (`cartId: 'order:<id>'`): this carries the order row's PRE-discount subtotal instead — a known pre-existing divergence between the two paths, not something to rely on; use `grossSubtotal`/`discountAmount` for the breakdown rows on both.
  """
  subtotal: Float!
  """
  The goods tax base: Total − Tax − delivery/shipping (net of discount, and of any embedded INCLUSIVE tax). Delivery is never part of it — it is its own row. Server-computed by the SAME rule on every path (cart, placed order, invoice) so this figure always matches what the admin portal shows for the same document — never derive it client-side.
  """
  taxableAmount: Float!
  """Total CUSTOMER/LOYALTY tier-discount savings across the cart."""
  tierDiscountAmount: Float
  """Buyer's effective CUSTOMER/LOYALTY tier discount %."""
  tierDiscountPercentage: Float
  """The total to pay."""
  total: Float!
  """The tax in the total."""
  vat: Float!
  """
  True when some/all of `vat` is already embedded in `subtotal` (INCLUSIVE tax) and is NOT added on top of `total`. Clients must render the VAT line as "included" rather than additive so the breakdown reconciles.
  """
  vatInclusive: Boolean!
  """
  Admin-configured tax display name (e.g. "VAT"/"GST"), sourced from TaxRate.name — never hardcode "VAT" client-side, since the org's configured tax can be named differently by country/config. Null when no line breakdown was resolvable (e.g. an all-exempt cart).
  """
  vatName: String
  """
  Effective blended VAT rate as a percentage of the taxable base (e.g. 14.7 = 14.7%), matching LineTaxInfo.rate's convention. Server-computed as vat / taxableBase * 100 — clients must render this instead of hardcoding a rate, since the org's TaxGroup can blend multiple TaxRate components.
  """
  vatRate: Float!
}

"""One item in the cart."""
type MobileCartItem {
  """
  Buyer consent that fulfilment may ship a manually-picked substitute if this line is unavailable. Consent + visibility only — no matching or suggestion logic exists behind it on any surface.
  """
  acceptAlternativeIfUnavailable: Boolean!
  """When the item was added."""
  addedAt: DateTime!
  """A placeholder for the image while it loads."""
  blurhash: String
  """
  Base units contained in one of this line's UOM (e.g. 30 for a case of 30 pcs). 1/undefined for the base unit.
  """
  conversionFactor: Float
  """Buyer's effective CUSTOMER/LOYALTY tier key for this line (e.g. GOLD)."""
  customerTier: String
  """The name of the discount that applied."""
  discountLabel: String
  "The unique ID of this record."
  id: ID!
  """The URL of the product image."""
  imageUrl: String
  """True when the item is in stock."""
  inStock: Boolean!
  """
  This line's discount — round(exact per-unit discount x quantity). `lineGross - lineDiscount` can sit one minor unit away from `lineTotal` on a half-cent line (833.50 - 375.08 = 458.42 against a true net of 458.43); that is the accepted per-line-accuracy trade-off the customer portal makes too, NOT a bug to 'fix' by re-deriving one row from the others.
  """
  lineDiscount: Float
  """
  This line's GROSS (pre-discount) amount — round(baseUnitPrice x quantity), computed server-side by the SAME expression the customer portal and admin use. Read it; never re-derive it as unitPrice x quantity on the client (the displayed unit price is rounded to cents and the charged one often is not).
  """
  lineGross: Float
  """The line total."""
  lineTotal: Float!
  """
  Largest orderable quantity for this line's UOM. Null/unset = unlimited.
  """
  maxOrderQuantity: Float
  """Smallest orderable quantity for this line's UOM (1 = unrestricted)."""
  minOrderQuantity: Float
  """A note on the line."""
  notes: String
  """Quantity step for this line's UOM (1 = no step restriction)."""
  orderMultiple: Float
  """The price of one unit before a discount."""
  originalUnitPrice: Float
  """Joined name(s) of every applied non-tier discount scheme."""
  otherDiscountLabel: String
  """Combined % from every applied non-tier discount scheme."""
  otherDiscountPercentage: Float
  "The ID of the product."
  productId: ID!
  """
  The PRODUCT's own image, for surfaces that group lines under a product header (the buyer-app basket does). `imageUrl` above is the LINE's image and is variant-first by design, so two variants of one product show different photos — but a product-level header showing the first variant's photo is simply the wrong picture next to the product name. Resolved server-side on every cart read/write, never stored on the line, so it is correct for carts that predate this field. Null when the product has no image of its own; callers fall back to `imageUrl`.
  """
  productImageUrl: String
  """The name of the product."""
  productName: String!
  """
  Quantity in the line's pack units. Fractional only for non-count packs (e.g. 1.5 KG), which the portal can add to the shared cart.
  """
  quantity: Float!
  """
  Per-unit saving from a genuine QUANTITY/bulk-order pricing tier (a VariantPrice qty-break, e.g. "3-10 units @ 900") — listUnitPrice minus the tier-resolved baseUnitPrice, BEFORE any customer/scheme discount. Independent of tierUnitDiscount above (which is the customer-tier amount); both can be non-zero on the same line, and their sum plus any other-discount amount equals the total per-unit saving.
  """
  quantityTierUnitDiscount: Float
  """
  Effective CUSTOMER/LOYALTY tier discount % applied to this line (not the quantity-break tier).
  """
  tierDiscountPercentage: Float
  """
  Exact per-unit CUSTOMER/LOYALTY tier discount amount (engine-accurate; the bill sums it).
  """
  tierUnitDiscount: Float
  """The unit of measure."""
  unitLabel: String
  """The price of one unit."""
  unitPrice: Float!
  """
  UOM the line is ordered in (each/case/carton). Drives the per-unit price resolution and the SalesOrder line UOM so displayed == charged.
  """
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
  """The label of the variant."""
  variantLabel: String
}

"""How a buyer pays at checkout: COD for cash on delivery, or ONLINE."""
enum MobileCheckoutPaymentMethod {
  """Pay cash on delivery."""
  COD
  """Pay online at checkout."""
  ONLINE
}

"""
Claims an invitation with an exact credential and signs in straight away, with no one-time code.
"""
input MobileClaimInviteInput {
  """The install handoff code."""
  handoffCode: String
  """
  Where the credential came from — LINK | REFERRER | CLIPBOARD. Logged for the funnel only; never trusted.
  """
  source: String
  """The subdomain of the organization."""
  subdomain: String
  """The invitation token."""
  token: String
}

"""A person on the buyer's account (name + optional title/email/phone)."""
type MobileContact {
  """The person's department."""
  department: String
  "Email address."
  email: String
  """The person's first name."""
  firstName: String
  "The unique ID of this record."
  id: ID!
  """The person's last name."""
  lastName: String
  """The person's full name."""
  name: String!
  "Phone number."
  phone: String
  """The person's job title."""
  title: String
  """The person's WhatsApp number."""
  whatsapp: String
}

"""
One attributed slice of an order line's discount. `kind` is TIER (the buyer's customer/loyalty tier scheme), SCHEME (any other configured scheme) or MANUAL (a keyed-in concession the pricing engine did not produce).
"""
type MobileDiscountLine {
  """
  This slice's LINE amount (already scaled by quantity) in the order currency.
  """
  amount: Float!
  """TIER | SCHEME | MANUAL"""
  kind: String!
  """Scheme name (or 'Manual discount') to render next to the amount."""
  label: String!
  """The scheme's declared percentage; null for an amount-only line."""
  percent: Float
}

"""A document address, as printable lines."""
type MobileDocumentAddress {
  """The lines of the address."""
  lines: [String!]!
  """The name on the address."""
  name: String
}

"""
A product this buyer orders repeatedly, derived from their own order history. Not a recommendation and not a promotion — it is the buyer's own past behaviour, which is why it carries the counts that justify it.
"""
type MobileFrequentProduct {
  """The URL of the product image."""
  imageUrl: String
  """When it was last ordered."""
  lastOrderedAt: DateTime!
  """Distinct orders containing this line."""
  orderCount: Int!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The pack it is usually ordered in."""
  uomId: ID!
  """
  The quantity this buyer typically orders — the MEDIAN, not the mean, so one bulk order does not distort the prefill.
  """
  usualQuantity: Float!
  "The ID of the product variant."
  variantId: ID!
  """The label of the variant."""
  variantLabel: String
}

"""What an invitation is for, shown on the accept screen."""
type MobileInviteInfo {
  """
  The invited email — prefilled and locked in the app so it is never typed.
  """
  email: String!
  """
  When the invite link stops working. The app stamps its resumable pending-invite entry with this, so the client never hardcodes the server's lifetime.
  """
  expiresAt: String
  """Company the invite is for, for the accept screen's subtitle."""
  partnerName: String!
}

"""Looks up an invitation."""
input MobileInviteInfoInput {
  """
  An install handoff code instead of the token — previews the invite (email + company) without spending it.
  """
  handoffCode: String
  """ARC org subdomain of this white-label build (see VerifyEmailOtpInput)."""
  subdomain: String
  """The invitation token."""
  token: String
}

"""
A buyer's sales invoice in full for the buyer app: lines, bill breakdown, payments received and addresses.
"""
type MobileInvoice {
  """The amount still owed."""
  balanceDue: Float!
  """The invoice's money, in the same shape as the cart and order bill."""
  bill: MobileCartBill!
  """The billing address."""
  billingAddress: MobileDocumentAddress
  "ISO 4217 currency code."
  currency: String!
  """The permanent reference of the person behind the billed order."""
  customerReferenceId: String
  """The date the invoice is due."""
  dueDate: DateTime
  "The unique ID of this record."
  id: ID!
  """The date of the invoice."""
  invoiceDate: DateTime!
  """The invoice number."""
  invoiceNumber: String!
  """The lines of the invoice."""
  items: [MobileInvoiceItem!]!
  """Notes for the buyer."""
  notes: String
  """The amount paid."""
  paidAmount: Float!
  """The payment terms."""
  paymentTerms: String
  """The payments applied to the invoice."""
  payments: [MobileInvoicePayment!]!
  "The ID of the sales order."
  salesOrderId: ID
  """The number of the order the invoice came from."""
  salesOrderNumber: String
  """The delivery address."""
  shippingAddress: MobileDocumentAddress
  """The order-level shipping charged on the invoice."""
  shippingAmount: Float!
  """The status of the invoice, such as PENDING, PARTIAL or PAID."""
  status: String!
  """The order-level surcharge on the invoice."""
  surchargeAmount: Float!
  """The terms of the invoice."""
  terms: String
}

"""
One invoice line as the buyer app shows it, drawn the same way as an order line.
"""
type MobileInvoiceItem {
  """The discount on the line."""
  discountAmount: Float
  """The discount on the line, in percent."""
  discountPercent: Float
  """The URL of the product image."""
  imageUrl: String
  """The line total, before tax."""
  lineTotal: Float!
  """
  The price of one unit before discount. Only set when it is above the charged price.
  """
  originalUnitPrice: Float
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """
  Billed quantity. Float, not Int: an invoice line can be a fractional weight or measure.
  """
  quantity: Float!
  """The unit of measure."""
  unitLabel: String
  """The price charged for one unit, after discount."""
  unitPrice: Float!
  "The ID of the unit of measure."
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
  """The label of the variant."""
  variantLabel: String
}

"""
A payment recorded against an invoice: one allocation, not the whole payment, because one receipt can settle several invoices.
"""
type MobileInvoicePayment {
  """
  The amount of the payment applied to this invoice, in the invoice currency.
  """
  amount: Float!
  "The unique ID of this record."
  id: ID!
  """How it was paid, as the seller recorded it."""
  method: String
  """When the payment was made."""
  paidAt: DateTime
  """The seller's receipt number."""
  paymentNumber: String
  """
  What kind of record this is: paymentReceived, paymentMade, creditNoteApplied or debitNoteApplied.
  """
  recordType: String
}

"""
A buying-list line the mobile cart could not take — the variant is gone, has no pack configured, or has no resolvable price. Reported rather than dropped, so the buyer is told what did NOT make it into the basket.
"""
type MobileListSkip {
  """Why the item was skipped."""
  reason: String!
  "The ID of the product variant."
  variantId: String!
}

"""
Order placed via the mobile BFF. v1 is COD only; persisted in Redis until SalesOrder wiring lands.
"""
type MobileOrder {
  "The ID of the address."
  addressId: ID!
  """
  Buyer amendment capabilities. Resolved on the single mobileOrder detail query and on the amendment mutations; absent (null) on list rows and on cancel.
  """
  amendment: MobileOrderAmendment
  """The order's money."""
  bill: MobileCartBill!
  """
  Permanent contact reference of the customer this order was placed for (Contact.referenceId). Absent when unresolvable — clients hide the line rather than showing a placeholder.
  """
  customerReferenceId: String
  """
  The live delivery option chosen at checkout (live-priced stores). Null for flat-fee orders. Detail query only.
  """
  deliverySelection: CustomerDeliverySelection
  """Delivery directions."""
  directions: String
  "The unique ID of this record."
  id: ID!
  """The key sent when the order was placed."""
  idempotencyKey: String!
  """The lines of the order."""
  items: [MobileOrderItem!]!
  """The order number."""
  orderNumber: String!
  """Amount captured by the online payment, in the order currency."""
  paidAmount: Float
  """When the online payment was recorded as succeeded."""
  paidAt: DateTime
  """How the order is paid."""
  paymentMethod: MobilePaymentMethod!
  """
  Our own receipt number (Payment.paymentNumber) for that online payment, when the Payment row exists.
  """
  paymentNumber: String
  """
  Customer-facing payment reference: the PSP's payment id (falling back to its session id). Absent unless an online payment SUCCEEDED for this order.
  """
  paymentReference: String
  """Where the payment stands."""
  paymentStatus: MobilePaymentStatus!
  """When the order was placed."""
  placedAt: DateTime!
  """
  Email of the customer's assigned sales rep — the buyer app renders it as a mailto: link. Absent when unassigned.
  """
  salesRepEmail: String
  """
  Name of the sales rep this customer is assigned to (Partner.assignedSalesRep). Absent when no rep is assigned — clients must hide the 'handled by' block rather than substituting anyone else.
  """
  salesRepName: String
  """
  Phone of the customer's assigned sales rep — the buyer app renders it as a tel: link. Absent when unassigned.
  """
  salesRepPhone: String
  """
  How much shipment tracking this customer gets in the buyer app (FULL when the store's setting does not apply to it). STATUS: show no shipment section (and no 'tracking will appear' line) — the order status alone. Detail query only; null on list rows.
  """
  shipmentTrackingLevel: CustomerTrackingLevel
  """
  Live outbound shipments of this order (oldest first): carrier, tracking (https link only), ETA and timeline. Never carries the seller's cost. Resolved on the mobileOrder detail query; absent on list rows.
  """
  shipments: [CustomerShipment!]
  """The ID of the delivery slot."""
  slotId: ID
  """The status of the order."""
  status: MobileOrderStatus!
}

"""
Buyer-side amendment capabilities for this order, resolved per request from the order state and the caller's role. Absent on list rows and on the cancel mutation.
"""
type MobileOrderAmendment {
  """
  The delivery address may be swapped for another of the company's addresses. Same gates as canEditItems, plus: never on an order placed for a branch, nor on one whose delivery fee was a live courier quote for its address.
  """
  canChangeAddress: Boolean!
  """
  The payment method may be changed. A SEPARATE gate from canEditItems: an ONLINE order (the ONLINE_PAYMENT lock above) is exactly the case this is for switching OFF of, so that lock does not apply here. Still requires a writer role, no live invoice, an amendable status, and nothing paid yet.
  """
  canChangePaymentMethod: Boolean!
  """
  Line quantities may be changed / lines removed. True only while the order is AWAITING_PAYMENT or CONFIRMED, nothing is paid, no live invoice references it, and the caller's role may write.
  """
  canEditItems: Boolean!
  """
  Why both capabilities are off: ROLE | INVOICED | ONLINE_PAYMENT | STATUS | PAID | BRANCH | NEGOTIATED_PRICE. Null when at least one is on (a negotiated-price order turns canEditItems off and keeps the address editable).
  """
  lockReason: String
  """
  Why canChangePaymentMethod is off: ROLE | INVOICED | STATUS | PAID. Null when it is on.
  """
  paymentMethodLockReason: String
  """
  Optimistic-concurrency version to echo back as expectedVersion on an amendment.
  """
  version: Int!
}

"""
Cursor-paginated list of buyer orders, read from Postgres (SalesOrder) scoped to the buyer's organization + partner. Redis is a read cache only — never the list's source of truth.
"""
type MobileOrderConnection {
  """True when there are more after this page."""
  hasNextPage: Boolean!
  """Opaque cursor for the next page. Null when there are no more results."""
  nextCursor: String
  """The orders on this page."""
  nodes: [MobileOrder!]!
  """How many orders there are in all."""
  totalCount: Int!
}

"""One line of an order."""
type MobileOrderItem {
  """
  True when the buyer agreed that a substitute may ship if the item becomes unavailable. It is saved when the order is placed and read-only here.
  """
  acceptAlternativeIfUnavailable: Boolean!
  """The discount charged on the line."""
  discountAmount: Float
  """The discount on the line, in percent."""
  discountPercent: Float
  """
  Per-line discount attribution — the split the cart bill showed. Empty when the line has no discount scheme lines (legacy orders too); clients render the list as-is and never re-derive it from unitPrice/originalUnitPrice.
  """
  discounts: [MobileDiscountLine!]!
  """The URL of the product image."""
  imageUrl: String
  """The line total."""
  lineTotal: Float!
  """
  The price of one unit before discount, saved when the order was placed.
  """
  originalUnitPrice: Float
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The smallest, largest and step quantity for this line."""
  qtyRules: LineQtyRules
  """
  Ordered quantity in the line's pack units (fractional only for non-count packs, e.g. 1.5 KG).
  """
  quantity: Float!
  """The unit of measure."""
  unitLabel: String
  """The price charged for one unit, after discount."""
  unitPrice: Float!
  "The ID of the unit of measure."
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
  """The label of the variant."""
  variantLabel: String
}

"""A new quantity for one order line."""
input MobileOrderLineQuantityInput {
  """
  Desired quantity for this line (whole units of the pack, >= 1). Omit a line to remove it.
  """
  quantity: Int!
  "The ID of the unit of measure."
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
}

"""
Live payment status for an order: combines order status + latest transaction status.
"""
type MobileOrderPaymentStatus {
  """The provider's exact error code."""
  errorCode: String
  """The provider's exact error message."""
  errorMessage: String
  """The ID of the order."""
  orderId: ID!
  """The status of the order."""
  orderStatus: String!
  """Where the payment stands."""
  status: MobilePaymentFlowStatus!
}

"""The status of an order as the buyer app shows it."""
enum MobileOrderStatus {
  """Waiting for payment."""
  AWAITING_PAYMENT
  """Cancelled."""
  CANCELLED
  """Confirmed by the seller."""
  CONFIRMED
  """Delivered."""
  DELIVERED
  """Fully invoiced."""
  INVOICED
  """With the courier for delivery."""
  OUT_FOR_DELIVERY
  """Some items are invoiced."""
  PARTIALLY_INVOICED
  """Some items have shipped."""
  PARTIALLY_SHIPPED
  """Placed by the buyer."""
  PLACED
  """Handed to the courier."""
  SHIPPED
}

"""
Event payload pushed via the orderUpdates subscription. v1 carries status changes; future revisions may add driver location and ETA refinements.
"""
type MobileOrderUpdate {
  """When the update was sent."""
  emittedAt: DateTime!
  """Free-text update detail (e.g. "Packed at warehouse")."""
  message: String
  """The ID of the order."""
  orderId: ID!
  """The order number."""
  orderNumber: String!
  """The new status of the order."""
  status: MobileOrderStatus!
}

"""
Result of createPaymentCheckout: the hosted checkout URL + order context.
"""
type MobilePaymentCheckout {
  """The address of the payment page."""
  checkoutUrl: String!
  """When the payment page stops working."""
  expiresAt: DateTime!
  """The ID of the order."""
  orderId: ID!
  """The order number."""
  orderNumber: String!
  """The ID of the payment transaction."""
  transactionId: ID!
}

"""
Where an online payment stands: PENDING, PAID, FAILED, EXPIRED or CANCELLED.
"""
enum MobilePaymentFlowStatus {
  """The buyer cancelled the payment."""
  CANCELLED
  """The payment link expired."""
  EXPIRED
  """The payment failed."""
  FAILED
  """The payment succeeded."""
  PAID
  """The payment is not finished."""
  PENDING
}

"""
How an order is paid: COD, ONLINE, EFT, or ON_ACCOUNT on the customer's credit terms.
"""
enum MobilePaymentMethod {
  """Cash on delivery."""
  COD
  """Electronic funds transfer."""
  EFT
  """Online payment."""
  ONLINE
  """Charged to the buyer's credit account."""
  ON_ACCOUNT
}

"""A payment method available at checkout (COD or ONLINE via a PSP)."""
type MobilePaymentOption {
  """The name of the payment gateway to show. Empty for cash on delivery."""
  label: String
  """How to pay."""
  method: MobileCheckoutPaymentMethod!
  """
  The payment provider, for example STRIPE. Empty for cash on delivery. Pass it when starting the payment.
  """
  provider: String
}

"""Where an order's payment stands: PENDING, COLLECTED, PAID or FAILED."""
enum MobilePaymentStatus {
  """The money was collected on delivery."""
  COLLECTED
  """The payment failed."""
  FAILED
  """Paid in full."""
  PAID
  """Not paid yet."""
  PENDING
}

"""The platform of a device: IOS, ANDROID or WEB."""
enum MobilePushPlatform {
  """An Android device."""
  ANDROID
  """An iOS device."""
  IOS
  """A web browser."""
  WEB
}

"""A device registered for push messages."""
type MobilePushToken {
  """The version of the app."""
  appVersion: String
  """The ID of the device."""
  deviceId: ID!
  """The platform of the device."""
  platform: MobilePushPlatform!
  """When the device was registered."""
  registeredAt: DateTime!
  """The push token."""
  token: String!
}

"""Gets a new access token from a refresh token."""
input MobileRefreshTokenInput {
  """
  The refresh JWT previously issued by verifyEmailOtp or refreshAccessToken.
  """
  refreshToken: String!
}

"""
A buyer registering themselves. The account waits for the seller's approval.
"""
input MobileRegisterBuyerInput {
  """
  Whether the buyer is a business or an individual. Recorded on `Partner.metadata.businessType`. Nullable because older app builds send none — omitted simply records nothing.
  """
  businessType: BuyerBusinessType
  """
  The 6-digit code the buyer already verified on the OTP screen, which now comes BEFORE this form. Re-checked server-side here because this mutation is what actually creates the account: without it, registration is callable directly and 'verified email' would be a client-side claim (Foundation Gate 3). Required.
  """
  code: String!
  """Company / business name."""
  companyName: String!
  """
  The person's department (e.g. 'Procurement'). Stored on their `Contact` rows, like `title`.
  """
  department: String
  "Email address."
  email: String!
  """
  Given name. Optional for older builds that send only `name`; when present it takes precedence over splitting `name`.
  """
  firstName: String
  """Family name. See `firstName`."""
  lastName: String
  """Contact/customer person name."""
  name: String!
  """
  Buyer's mobile number in E.164 form (e.g. +97455551234). Persisted to User.phone. Nullable in the SCHEMA for backward compatibility only — app builds predating this field send nothing, and a required field would fail their signup at GraphQL validation before the resolver runs. Current clients treat it as MANDATORY and gate the Sign Up CTA on it.
  """
  phone: String
  """
  ARC org subdomain this white-label build is pinned to (Constants.expoConfig.extra.orgSubdomain). Determines which tenant the customer is created under. Optional only for backward-compat / dev fallback (MOBILE_BUYER_ORG_ID).
  """
  subdomain: String
  """
  The person's job title (e.g. 'Purchasing Manager'). Stored on their `Contact` rows — there is no title column on `User`.
  """
  title: String
  """
  Buyer's WhatsApp number in E.164 form. Persisted as its own WHATSAPP `Contact` channel row — there is no WhatsApp column on `User`. Optional: the form lets it be left blank or copied from the mobile number.
  """
  whatsapp: String
}

"""Removes an item from the cart."""
input MobileRemoveCartItemInput {
  """The ID of the cart item."""
  itemId: ID!
}

"""
A reordered line whose price today differs from what the buyer paid on the original order. Reorder deliberately re-prices, so this is how the difference gets SHOWN rather than discovered at checkout.
"""
type MobileReorderPriceChange {
  """Unit price today."""
  nowUnitPrice: Float!
  """The name of the product whose price changed."""
  productName: String!
  "The ID of the product variant."
  variantId: String!
  """Unit price on the original order."""
  wasUnitPrice: Float!
}

"""
Result of re-adding a past order to the mobile cart. A summary, not a bare cart: reorder re-prices at today's catalogue and can skip a line, and a buyer who taps once must be told both.
"""
type MobileReorderResult {
  """Lines merged onto the cart."""
  addedCount: Int!
  """The cart after the reorder."""
  cart: MobileCart!
  """
  Of `addedCount`, how many were ALREADY in the basket and had their quantity topped up rather than being added fresh. Reordering the same order twice doubles those lines — the app must be able to say so, or a buyer silently ends up with 50 of a 25-unit line.
  """
  mergedCount: Int!
  """Lines that cost something different today."""
  priceChanged: [MobileReorderPriceChange!]!
  """
  Lines that could not be re-added at all — a free-text line, or a variant the catalogue no longer prices.
  """
  skipped: [MobileListSkip!]!
}

"""Changes an item in the cart."""
input MobileUpdateCartItemInput {
  """
  True when the buyer allows a substitute if the item becomes unavailable.
  """
  acceptAlternativeIfUnavailable: Boolean
  """The ID of the cart item."""
  itemId: ID!
  """The new quantity. 0 removes the line."""
  quantity: Int!
}

"""Stock movements of one type."""
type MovementSlice {
  """How many movements."""
  count: Int!
  """The quantity moved."""
  quantity: Float!
  """The cost of the movements."""
  totalCost: Float!
  """The movement type."""
  type: String!
}

"""The status of stock movement"""
enum MovementStatus {
  """Cancelled."""
  CANCELLED
  """Done."""
  COMPLETED
  """Under way."""
  IN_PROGRESS
  """Not started."""
  PENDING
}

"""The type of stock movement"""
enum MovementType {
  """A change from a stock adjustment."""
  ADJUSTMENT
  """A change from a cycle count."""
  CYCLE_COUNT
  """Stock leaving a warehouse."""
  ISSUE
  """Stock arriving in a warehouse."""
  RECEIPT
  """Stock coming back from a return."""
  RETURN
  """Stock moving between warehouses."""
  TRANSFER
}

type Mutation {
  """
  Public: no authentication required.
  
  Accepts a customer-user invitation from its link and signs the invited person in. The link works once and expires. The person then signs in with one-time codes, never a password.
  """
  acceptCustomerInvite(
    """The invitation token from the link."""
    input: AcceptCustomerInviteInput!
  ): CustomerAuthResponse!
  """
  Requires permission `customers:customer:update`.
  
  Dismisses the reassigned-to-you flag on a customer. Only the assigned sales rep, or a user who can see all customers, may acknowledge. Needs the customers update permission. Returns true on success.
  """
  acknowledgeCustomerReassignment(
    """The ID of the customer."""
    customerId: ID!
  ): Boolean!
  """
  Requires at least one of the permissions `settings:currency:update` or `settings:tenant:update`.
  
  Turns a currency on for the organization only. Requires permission to update currency or tenant settings.
  """
  activateCurrency(
    """The ID of the currency."""
    id: String!
  ): Currency!
  """
  Requires a tenant administrator.
  
  Approves a customer so it becomes active, typically one that registered itself and is waiting in the pending queue. Can assign the owning sales rep in the same step. Tenant admins only.
  """
  activateCustomer(
    """
    The sales rep to set as the customer's owner on approval. Leave it out to approve without assigning a rep. Must be a user in your organization.
    """
    assignedSalesRepId: ID
    """The ID of the customer."""
    id: ID!
  ): Customer!
  """
  Requires permission `products:discount:update`.
  
  Turns a discount scheme on. A percentage scheme whose percentage is out of range cannot be activated. Needs the permission to edit discounts.
  """
  activateDiscountScheme(
    """The ID of the discount scheme."""
    id: String!
  ): DiscountScheme!
  """
  Requires an authenticated session.
  
  Adds people to a channel. Every person must belong to the same organization as the channel, otherwise the whole request is refused. Only an admin or manager, or an admin of that channel, can do this. Needs a signed-in user.
  """
  addChannelMembers(
    """The ID of the chat channel."""
    channelId: String!
    """The IDs of the people to add."""
    memberIds: [String!]!
  ): ChatChannel!
  """
  Requires a customer (portal or buyer app) session.
  
  Add a person to the buyer's account.
  """
  addContact(
    """The details of the mobile contact to add."""
    input: AddMobileContactInput!
  ): MobileContact!
  """
  Requires at least one of the permissions `settings:currency:create` or `settings:tenant:update`.
  
  Add additional currency for multi-currency support. Requires permission to create currencies or update tenant settings.
  """
  addCurrency(
    """The details of the currency to add."""
    input: AddCurrencyInput!
  ): Boolean!
  """
  Requires at least one of the permissions `settings:organization:update` or `settings:tenant:update`.
  
  Adds a custom hostname for the portal. The name must be a valid hostname that is not reserved, not on the platform's own domain and not registered by any organization. It starts as pending until its setup completes. Needs settings:organization:update, or settings:tenant:update.
  """
  addOrganizationDomain(
    """The hostname to add."""
    input: AddOrganizationDomainInput!
  ): OrganizationDomain!
  """
  Requires permission `products:product:update`.
  
  Adds a value to a product attribute. Requires permission to update products.
  """
  addProductAttributeValue(
    """The attribute and its new value."""
    input: AddProductAttributeValueInput!
  ): ProductAttributeChangeResult!
  """
  Requires permission `products:product:update`.
  
  Add a unit (pack) to a product or to one of its variants. The same unit cannot be added twice to the same product or variant. Only the product's own base unit can be marked base, and a variant can have at most 3 sellable units. Needs the products update permission.
  """
  addProductUOM(
    """The product unit (pack) to add."""
    data: CreateProductUOMInput!
  ): ProductUOM!
  """
  Requires a customer (portal or buyer app) session.
  
  Adds a variant to the cart, or raises its quantity if the line exists. Pass the cart revision you last saw, and an operation ID so a retry does not add twice.
  """
  addToCart(
    """
    The product, variant, unit of measure and quantity, with optional notes, whether an alternative is accepted if it is out of stock, the expected cart revision and the operation ID.
    """
    input: AddToCartInput!
  ): CartType!
  """
  Requires permission `visits:visit:execute`.
  
  Adds an unplanned visit to a customer on the signed-in rep's route. The customer must be in the rep's book, or their team's or the organization's according to their visibility. Requires permission to run visits.
  """
  addUnplannedVisit(
    """The day of the visit. Omit it for today."""
    date: DateTime
    """
    True to return the rep's existing stop for this customer and day instead of adding a second one. Omit it to allow a second visit on the same day.
    """
    onlyIfNotScheduled: Boolean
    """The ID of the customer to visit."""
    partnerId: ID!
  ): Visit!
  """
  Requires permission `users:user:update`.
  
  Adds a reporting relationship between two users in your organization. Needs users:user:update.
  """
  addUserRelationship(
    """The users and the type of relationship to add."""
    input: CreateUserRelationshipInput!
  ): UserRelationship!
  """
  Requires permission `payments:bank-account:update`.
  
  Moves a bank account's running balance by a signed amount with a reason: positive to add, negative to reduce. A zero adjustment is refused. This is the only way to change the balance outside a processed payment, and the change is audited. Requires permission to update bank accounts.
  """
  adjustBankAccountBalance(
    """The ID of the bank account."""
    id: ID!
    """The signed amount and the reason for the adjustment."""
    input: AdjustBankAccountBalanceInput!
  ): BankAccount!
  """
  Requires permission `customers:customer:update`.
  
  Adjust a customer's credit. type is INCREASE_LIMIT, DECREASE_LIMIT, ADJUST_BALANCE or PAYMENT_RECEIVED; any other type is refused. A reason is required and the change is audited. Needs the customers update permission (the same grant that edits the credit limit on the customer form).
  """
  adjustCustomerCredit(
    """The amount of the adjustment."""
    amount: Float!
    """The ID of the customer."""
    customerId: String!
    """Optional notes about the adjustment."""
    notes: String
    """Why the credit is being adjusted. Required."""
    reason: String!
    """Optional reference for the adjustment."""
    reference: String
    """INCREASE_LIMIT, DECREASE_LIMIT, ADJUST_BALANCE or PAYMENT_RECEIVED."""
    type: String!
  ): Customer!
  """
  Requires permission `inventory:stock_adjustment:create`.
  
  Corrects the stock quantity, the cost, or both, of one product variant in a warehouse by recording an ADJUSTMENT movement. It must change quantity or cost, the warehouse, variant and unit of measure must exist in your organization, and an adjustment cannot take stock below zero unless your inventory settings allow negative stock. An idempotency key makes a retry return the original movement. Needs the stock adjustment create permission.
  """
  adjustInventory(
    """The details of the adjust inventory request."""
    input: AdjustInventoryInput!
  ): StockMovement!
  """
  Requires a tenant administrator.
  
  Activates or deactivates a buyer's shipping or delivery address. An active address can be ordered against, and activating one also promotes a customer still waiting for approval to active. Tenant admins only. Returns true on success.
  """
  adminSetAddressActive(
    """The ID of the address."""
    addressId: ID!
    """True to activate the address, false to deactivate it."""
    isActive: Boolean!
  ): Boolean!
  """
  Requires at least one of the permissions `payments:payment:allocate` or `purchase:payment:allocate`.
  
  Applies a payment's unallocated balance to one or more invoices of the same customer or supplier. At least one allocation is required. The payment must still be allocatable (a voided, reversed or refunded payment is refused), the payment and each invoice must share a currency, and the total cannot exceed the payment's unallocated amount or an invoice's outstanding amount.
  """
  allocatePayment(
    """The payment and the invoices to allocate it to."""
    input: AllocatePaymentInput!
  ): Payment!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:create`, `payments:collection:create`, `payments:collection:update`, `payments:payment:allocate`, `payments:payment:create`, `payments:payment:update`, `purchase:grn:create`, `purchase:grn:update`, `purchase:payment:allocate`, `purchase:payment:create`, `purchase:payment:update`, `purchase:purchase_invoice:create`, `purchase:purchase_order:approve`, `sales:credit_note:create`, `sales:sales_order:confirm`, `sales:sales_order:deliver`, `sales:sales_order:ship`, `sales:sales_order:update`, `sales:shipment:create` or `sales:shipment:update`.
  
  Runs the held action of an approved request you raised, as you, so every control checks it again. It runs at most once: a request already applied, or being applied by someone else right now, is refused without running it. You need the action's own permission.
  """
  applyControlRequest(
    """The approval request's ID."""
    id: ID!
  ): ControlApprovalApplyResult!
  """
  Requires permission `sales:credit_note:update`.
  
  Applies an amount of an APPROVED credit note to a sales invoice, reducing what the customer owes on it. The amount must be positive and cannot exceed the note's remaining amount. The invoice must be a sales invoice of the same customer, in the same currency, and in a status that can still take payment.
  """
  applyCreditNote(
    """The amount to apply against the invoice."""
    amount: Float!
    """The ID of the credit note."""
    id: ID!
    """The ID of the sales invoice to apply the credit to."""
    invoiceId: ID!
  ): CreditNote!
  """
  Requires permission `purchase:debit_note:update`.
  
  Applies an amount of a PENDING or partially applied debit note to a purchase invoice, reducing what you owe the supplier on it. The amount must be positive and within the note's remaining amount. The invoice must be of the same supplier and in the same currency. Needs the debit notes feature on your plan.
  """
  applyDebitNote(
    """The amount to apply against the invoice."""
    amount: Float!
    """The ID of the debit note."""
    id: ID!
    """The ID of the purchase invoice to apply the debit to."""
    invoiceId: ID!
  ): DebitNoteResponse!
  """
  Requires permission `catalog:copilot:apply`.
  
  THE write gate: applies an explicitly APPROVED proposal card through the throttled, idempotent pipeline. Anything else (PROPOSED/REJECTED/…) fails 400.
  """
  applyProposal(
    """The details of the apply proposal request."""
    input: ApplyProposalInput!
  ): ApplyProposalResult!
  """
  Requires at least one of the permissions `purchase:debit_note:update` or `sales:credit_note:update`.
  
  Sets the restocking fee on a return and saves the reason in the return's notes. The fee replaces any earlier one. Needs the update permission of the return's direction.
  """
  applyRestockingFee(
    """The restocking fee to charge."""
    feeAmount: Float!
    """Why the fee is applied. It is saved in the return's notes."""
    reason: String!
    """The ID of the return."""
    returnId: String!
  ): ReturnResponse!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve` or `purchase:purchase_order:approve`.
  
  Approves a pending approval request, then runs its held action as you, so every control checks it again and the action's own rules apply. The approval is recorded even when the action does not run (for example when you lack the action's permission, or another control refuses); the result says why, and the request stays approved for someone to apply. Same signer rules as approveControlRequest.
  """
  approveAndApplyControlRequest(
    """The approval request's ID."""
    id: ID!
    """An optional note, up to 500 characters."""
    note: String
  ): ControlApprovalApplyResult!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve` or `purchase:purchase_order:approve`.
  
  Approves a pending approval request. Approving records your signature only: the held action still has to be run. You cannot approve a request you raised, or one you already acted on, and you need the approval permission the request names.
  """
  approveControlRequest(
    """The approval request's ID."""
    id: ID!
    """An optional note, up to 500 characters."""
    note: String
  ): ControlApprovalRequest!
  """
  Requires permission `catalog:copilot:chat`.
  
  Approve one card of the open approval request from a push deep-link, on the caller's own session. Refused for a closed or stale request, a changed card, or a critical card (approve those in the chat).
  """
  approveCopilotAskFromLink(
    """The ID of the approval request."""
    askId: String!
    """The ID of the proposal."""
    proposalId: ID!
    """The ID of the Copilot session."""
    sessionId: ID!
  ): ProposalCardType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Approves a change the copilot proposed in the caller's own chat, as the signed-in person. Approving does not write anything: applyProposal does that. An approval is refused when the proposal has been superseded, still has blockers, or is in a state that cannot be approved. A change that touches a role also needs the approver to hold every permission involved and to type the role's name as the confirmation. Limited to 30 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  approveCopilotProposal(
    """
    The role's name, typed out. Needed only for a proposal that changes a role.
    """
    confirmation: String
    """The ID of the proposal."""
    proposalId: ID!
    """The ID of the copilot chat the proposal is in."""
    sessionId: ID!
  ): ProposalCardType!
  """
  Requires permission `products:import:approve`.
  
  The human approval gate — locks the commit mode, resolves shared references, and enqueues the chunked commit.
  """
  approveProductImport(
    """The details of the approve product import request."""
    input: ApproveProductImportInput!
  ): Boolean!
  """
  Requires permission `purchase:purchase_order:approve`.
  
  Approves a purchase order: a DRAFT or SUBMITTED order becomes APPROVED. Any other status is refused. Needs the purchase order approve permission and the purchase orders feature on your plan.
  """
  approvePurchaseOrder(
    """
    The version of the record you last read. The change is refused if someone else changed it since.
    """
    expectedVersion: Int
    """The ID of the purchase order."""
    id: ID!
  ): PurchaseOrder!
  """
  Requires at least one of the permissions `purchase:debit_note:approve` or `sales:credit_note:approve`.
  
  Approves a return request on the terms given. A rejected, cancelled or completed return cannot be approved, and approving a return that is already approved changes nothing. Approving a purchase return posts its stock and debit note. Needs the approve permission of the return's direction: credit notes approve for a customer return, debit notes approve for a supplier return.
  """
  approveRMA(
    """The ID of the return."""
    returnId: String!
    """The conditions of the approval, one per entry."""
    terms: [String!]!
  ): ReturnResponse!
  """
  Requires permission `settings:controls:manage`.
  
  Archives a control: it switches off and stays in the history. Requires settings:controls:manage.
  """
  archiveControl(
    """The control to archive and why."""
    input: ArchiveControlInput!
  ): ControlRuleType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Archives one of the caller's own copilot chats. A colleague's chat, or an unknown ID, reads as missing. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  archiveCopilotSession(
    """The ID of the copilot chat."""
    id: ID!
  ): CopilotSession!
  """
  Requires a customer (portal or buyer app) session.
  
  assign managers to a branch (CUSTOMER_ADMIN only). Targets must be same-partner CUSTOMER users; CUSTOMER_VIEWER is allowed (EDGE).
  """
  assignBranchManagers(
    """The ID of the address."""
    addressId: ID!
    """The IDs of the users."""
    userIds: [ID!]!
  ): CustomerBranch!
  """
  Requires permission `products:discount:update`.
  
  Replaces the categories a discount scheme applies to with the list given. The existing assignments are removed first, and the scheme and every category must belong to the organization. Needs the discounts update permission.
  """
  assignCategoriesToScheme(
    """The IDs of the categories the scheme should apply to."""
    data: AssignCategoriesDto!
    """The ID of the discount scheme."""
    schemeId: String!
  ): Boolean!
  """
  Requires a tenant administrator.
  
  Assigns the given customers to one sales rep and reports, for each, whether it succeeded. Each change is audited and leaves the same handoff trail as any other reassignment. Tenant admins only.
  """
  assignCustomersToRep(
    """The sales rep and the IDs of the customers to assign to them."""
    input: AssignCustomersToRepInput!
  ): BulkPendingActionResult!
  """
  Requires permission `products:discount:update`.
  
  Replaces the customers a discount scheme applies to with the list given. The existing assignments are removed first, and the scheme and every customer must belong to the organization. Needs the discounts update permission.
  """
  assignCustomersToScheme(
    """The IDs of the customers the scheme should apply to."""
    data: AssignCustomersDto!
    """The ID of the discount scheme."""
    schemeId: String!
  ): Boolean!
  """
  Requires permission `settings:permission:update`.
  
  Grants a permission to a role. Returns true on success. Needs settings:permission:update.
  """
  assignPermissionToRole(
    """The role and the permission to grant."""
    input: AssignPermissionInput!
  ): Boolean!
  """
  Requires permission `products:brand:update`.
  
  Assign existing products to a brand. Products already on another brand are moved; ones already on this brand are skipped. Needs the brands update permission.
  """
  assignProductsToBrand(
    """The ID of the brand."""
    brandId: ID!
    """The IDs of the products."""
    productIds: [ID!]!
  ): BrandProductAssignmentResult!
  """
  Requires permission `products:product:update`.
  
  Assign existing products to a category. Products already in the category are skipped.
  """
  assignProductsToCategory(
    """The ID of the category."""
    categoryId: ID!
    """The IDs of the products."""
    productIds: [ID!]!
  ): CategoryProductAssignmentResult!
  """
  Requires permission `products:discount:update`.
  
  Replaces the products a discount scheme applies to with the list given. The existing assignments are removed first, and the scheme and every product must belong to the organization. Needs the discounts update permission.
  """
  assignProductsToScheme(
    """The IDs of the products the scheme should apply to."""
    data: AssignProductsDto!
    """The ID of the discount scheme."""
    schemeId: String!
  ): Boolean!
  """
  Requires permission `settings:permission:update`.
  
  Grants a permission directly to a user. Returns true on success. Needs settings:permission:update.
  """
  assignUserPermission(
    """The user and the permission to grant."""
    input: AssignUserPermissionInput!
  ): Boolean!
  """
  Requires permission `settings:role:update`.
  
  Assigns a user to a role. Returns true on success. Needs settings:role:update.
  """
  assignUserToRole(
    """The user and the role to assign them to."""
    input: AssignUserToRoleInput!
  ): Boolean!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:export`, `inventory:stock_transfer:export`, `payments:collection:export`, `payments:invoice:export`, `payments:payment:export`, `purchase:grn:export`, `purchase:payment:export`, `purchase:purchase_invoice:export`, `purchase:purchase_order:export` or `sales:sales_order:export`.
  
  Checks that you may export the given document type and says whether the organization requires the export to be encrypted. It writes nothing, so it is safe to call when an export dialog opens. Needs the export permission for that document type.
  """
  authorizeExport(
    """
    The export key that identifies the document type, and the label of the record being exported.
    """
    input: AuthorizeExportInput!
  ): AuthorizeExportResult!
  """
  Requires the permissions `products:tax:create` and `settings:tenant:update`.
  
  Sets up tax for a country in one step: adds the country's standard tax rates and creates its standard tax groups. Needs both the tax create and the tenant settings update permissions.
  """
  autoConfigureTax(
    """The country to set up tax for."""
    countryCode: String!
    """
    The currency code to configure the country's tax with. Omit it to use the organization's.
    """
    currency: String
  ): AutoConfigureTaxResult!
  """
  Requires permission `sales:shipment:create`.
  
  Books a courier to collect a customer return, using one of your delivery partners that is set up for returns. The booking is all-or-nothing and shows the carrier's own error if it fails. Needs the delivery partners feature on your plan and the shipment create permission.
  """
  bookReturnPickup(
    """The courier booking details."""
    delivery: ShipmentBookingInput!
    """The ID of the product return."""
    productReturnId: ID!
  ): ShipmentGql!
  """
  Requires permission `sales:shipment:create`.
  
  Books a courier for goods that have already shipped from a sales order. It never issues stock. When every shipped item on the order is already covered by a shipment, it is refused and asks you to ship the remaining items first. Needs the delivery partners feature on your plan and the shipment create permission.
  """
  bookShipmentForShippedGoods(
    """The details of the shipment for shipped goods to book."""
    input: BookShipmentForShippedGoodsInput!
  ): [ShipmentGql!]!
  """
  Requires a tenant administrator.
  
  Approves many pending customers in one call and reports, for each, whether it succeeded. Tenant admins only.
  """
  bulkActivatePendingCustomers(
    """The pending customers to approve."""
    target: PendingBulkTargetInput!
  ): BulkPendingActionResult!
  """
  Requires a tenant administrator.
  
  Assigns many pending customers to one sales rep and reports, for each, whether it succeeded. Tenant admins only.
  """
  bulkAssignPendingCustomers(
    """The IDs of the customers to assign."""
    customerIds: [ID!]!
    """The ID of the sales rep who will own the customers."""
    newRepId: ID!
  ): BulkPendingActionResult!
  """
  Requires permission `products:product:create`.
  
  Creates products from a list of rows, each with a product name, SKU and optional category, brand, prices, cost, stock and unit. Missing categories and brands are created by name. Rows are processed one by one; the result lists what was created and the error for each row that failed. Requires permission to create products.
  """
  bulkCreateProducts(
    """The rows to create."""
    input: BulkCreateProductsInput!
  ): BulkCreateProductsResult!
  """
  Requires permission `products:product:delete`.
  
  Soft-delete a set of variants by id. Never leaves a product variant-less (per-item LAST_VARIANT failure) and promotes a new default variant when the default is deleted.
  """
  bulkDeleteProductVariants(
    """The details of the product variant bulk delete request."""
    input: ProductVariantBulkDeleteInput!
  ): ProductBulkOperation!
  """
  Requires permission `products:product:delete`.
  
  Soft-delete a validated set of products (explicit ids, or all-matching-filter with expectedTotal). ≤50 runs inline; larger targets run as a background job — poll productBulkOperation.
  """
  bulkDeleteProducts(
    """Which products to delete."""
    target: ProductBulkTargetInput!
  ): ProductBulkOperation!
  """
  Requires permission `categories:category:create`.
  
  Imports categories from a CSV or spreadsheet file. By default it only validates the file and reports each row's errors without saving. Set updateExisting to also update categories whose code already exists, which needs permission to update categories. Requires permission to create categories.
  """
  bulkImportCategories(
    """
    The file content, its format, whether to only validate, and whether to update existing categories.
    """
    input: BulkCategoryImportInput!
  ): BulkCategoryImportResult!
  """
  Requires at least one of the permissions `payments:invoice:import` or `purchase:purchase_invoice:import`.
  
  Imports many invoices from a file in one call. The result reports how many rows succeeded and failed and lists the errors, so you can correct and resubmit the failed rows. Needs the invoice import permission for sales invoices, or the purchase invoices import permission for purchase invoices.
  """
  bulkImportInvoices(
    """The import file and options."""
    input: BulkImportInvoicesInput!
  ): BulkImportResult!
  """
  Requires permission `purchase:purchase_order:create`.
  
  Imports purchase orders from a CSV or Excel file, grouping rows into orders by order number. Each order needs a supplier, an order date in YYYY-MM-DD form, and lines with a product or variant identifier and a quantity above 0. The result reports what was created and what failed. Needs the purchase order create permission and the purchase orders feature on your plan.
  """
  bulkImportPurchaseOrders(
    """The details of the bulk import request."""
    input: BulkImportInput!
  ): PurchaseOrderBulkImportResult!
  """
  Requires permission `sales:sales_order:import`.
  
  Create or update many sales orders from one import payload. Returns the success and failure counts and an error entry for each rejected row.
  """
  bulkImportSalesOrders(
    """The import payload."""
    input: BulkImportInput!
  ): SalesOrderBulkImportResult!
  """
  Requires permission `products:tax:import`.
  
  Imports tax groups from an uploaded file. It can validate the file without saving, and can update groups that already exist. Needs the tax import permission.
  """
  bulkImportTaxGroups(
    """
    The file content, its format, whether to only validate, and whether to update existing groups.
    """
    input: BulkImportInput!
  ): TaxGroupBulkImportResult!
  """
  Requires a tenant administrator.
  
  Moves every customer owned by one sales rep to another, for example when a rep leaves. Future orders go to the new rep; past orders and commissions stay with the old one. Returns how many customers were moved. Tenant admins only.
  """
  bulkReassignCustomers(
    """The ID of the sales rep who currently owns the customers."""
    fromRepId: ID!
    """The ID of the sales rep who will own the customers."""
    toRepId: ID!
  ): BulkReassignResult!
  """
  Requires a tenant administrator.
  
  Rejects many pending customers in one call by setting them inactive, and reports, for each, whether it succeeded. Tenant admins only.
  """
  bulkRejectPendingCustomers(
    """Why the customers are being rejected. Optional."""
    reason: String
    """The pending customers to reject."""
    target: PendingBulkTargetInput!
  ): BulkPendingActionResult!
  """
  Requires permission `products:discount:update`.
  
  Updates several discount schemes in one call, each with its own changes, and records an audit entry for each scheme that changed. Needs the discounts update permission.
  """
  bulkUpdateDiscountSchemes(
    """The list of schemes and the changes to make to each."""
    data: BulkUpdateDiscountSchemeDto!
  ): Boolean!
  """
  Requires permission `settings:tenant:update`.
  
  Changes several settings in one call. A category that has its own update operation is refused. Needs settings:tenant:update.
  """
  bulkUpdateTenantSettings(
    """The settings to change, each with its ID and new values."""
    input: BulkUpdateSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `suppliers:supplier:update`.
  
  Recomputes the rating of every supplier in the organization and returns one result per supplier. Needs the suppliers update permission.
  """
  calculateAllSupplierRatings: [SupplierRatingResult!]!
  """
  Requires permission `suppliers:supplier:update`.
  
  Recomputes one supplier's rating from its goods receipts. Returns success false with a message when there is no goods receipt data. Needs the suppliers update permission.
  """
  calculateSupplierRating(
    """The ID of the supplier."""
    supplierId: ID!
  ): SupplierRatingResult!
  """
  Requires permission `products:tax:read`.
  
  Calculates the tax on a base amount for a tax group, specific tax rates or a location, and saves nothing. Requires permission to read tax.
  """
  calculateTax(
    """
    The base amount and what to tax it by: a tax group, tax rates, or a location, with optional product categories and currency.
    """
    input: TaxCalculationInput!
  ): TaxCalculation!
  """
  Requires permission `purchase:debit_note:update`.
  
  Cancels a debit note. A note that has been applied, fully or partly, cannot be cancelled. Needs the debit notes feature on your plan.
  """
  cancelDebitNote(
    """The ID of the debit note."""
    id: ID!
  ): DebitNoteResponse!
  """
  Requires at least one of the permissions `payments:invoice:cancel` or `purchase:purchase_invoice:cancel`.
  
  Cancels an invoice and reverses what it caused: payment allocations on it are reversed, shipped quantities are restored on the source order, and the order's invoice status is recalculated. Money already settled against the invoice is given back through a credit note (sales invoice) or a debit note (purchase invoice). Call `invoiceCancellationPreview` first; the cancellation is refused if blockers exist or if the allocations changed since you read them.
  """
  cancelInvoice(
    """The ID of the invoice."""
    id: ID!
    """
    Whether to also reverse the payments allocated to the invoice. Defaults to false. Use invoiceCancellationPreview to see the effect first.
    """
    reverseAllocations: Boolean! = false
  ): Invoice!
  """
  Requires a customer (portal or buyer app) session.
  
  Cancels an order the buyer placed. Delegates to the canonical orders.service.ts cancellation — rejects orders already SHIPPED/DELIVERED/CANCELLED/RETURNED, or with an open invoice (backend returns the exact reason).
  """
  cancelMobileOrder(
    """The ID of the order."""
    orderId: ID!
    """Why the order is cancelled."""
    reason: String
  ): MobileOrder!
  """
  Requires a customer (portal or buyer app) session.
  
  Abandon an online checkout the buyer backed out of: verifies the session with the PSP (a session that turns out PAID is captured normally and reported with paid: true, never cancelled), best-effort voids the hosted link, then cancels the AWAITING_PAYMENT order. Idempotent — an order already terminal returns its current state.
  """
  cancelPaymentCheckout(
    """The ID of the order."""
    orderId: ID!
  ): MobileCancelCheckout!
  """
  Requires permission `products:import:stage`.
  
  Cancels an import before commit has started.
  """
  cancelProductImport(
    """The ID of the import."""
    importId: String!
  ): Boolean!
  """
  Requires permission `purchase:purchase_order:update`.
  
  Cancels a purchase order. It is allowed from DRAFT, SUBMITTED, APPROVED and PARTIALLY_RECEIVED. With nothing received the order becomes CANCELLED. Once goods are received, only the quantity not yet received is cancelled: the received goods and their receipts stay, the order ends RECEIVED (short closed), no further receipt can be posted, and a reason is required. A RECEIVED, CANCELLED or CLOSED order cannot be cancelled again. Needs the purchase orders feature on your plan.
  """
  cancelPurchaseOrder(
    """The ID of the purchase order."""
    id: ID!
    """Why the purchase order is cancelled."""
    reason: String
  ): PurchaseOrder!
  """
  Requires permission `sales:sales_order:cancel`.
  
  Cancel an order, optionally with a reason. Orders already shipped, delivered, cancelled or returned cannot be cancelled, and an order with a live invoice must have the invoice cancelled first.
  """
  cancelSalesOrder(
    """The ID of the sales order."""
    id: ID!
    """Why the order is being cancelled."""
    reason: String
  ): SalesOrder!
  """
  Requires permission `sales:shipment:cancel`.
  
  Cancels a shipment with the carrier, with an optional `reason`. Stock is not returned: a return does that. A shipment the courier already holds (picked up, in transit or out for delivery) or one that has finished cannot be cancelled, and that is checked before the carrier is contacted. Needs the delivery partners feature on your plan and the shipment cancel permission.
  """
  cancelShipment(
    """The ID of the shipment."""
    id: ID!
    """Why the shipment is cancelled."""
    reason: String
  ): ShipmentGql!
  """
  Requires permission `storefront:storefront:update`.
  
  Stop an edit job. Aborts the model call when this API instance runs the job and returns it CANCELLED; on another instance the job stops at its next model turn, so keep polling. A job that already ended is returned unchanged. Credits already charged stay charged (creditsUsedCents).
  """
  cancelStorefrontEditGeneration(
    """The edit job to stop, as startStorefrontEditGeneration returned it."""
    jobId: ID!
  ): StorefrontEditJob!
  """
  Requires permission `storefront:storefront:update`.
  
  Stop a page-generation job. Aborts the model call when this API instance runs the job and returns it CANCELLED; on another instance the job stops at its next model turn, so keep polling. A job that already ended is returned unchanged. Credits already charged stay charged (creditsUsedCents).
  """
  cancelStorefrontPageGeneration(
    """The ID of the page generation job."""
    jobId: ID!
  ): StorefrontPageJob!
  """
  Requires permission `storefront:storefront:update`.
  
  Stop a section-generation job (the editor's Stop button). Aborts the model call when this API instance runs the job and returns it CANCELLED; on another instance the job stops at its next model turn, so keep polling (if that instance is gone, the poll reads CANCELLED about a minute after the job's last update). A job that already ended is returned unchanged. Credits already charged stay charged (creditsUsedCents).
  """
  cancelStorefrontSectionGeneration(
    """The ID of the section generation job."""
    jobId: ID!
  ): StorefrontSectionJob!
  """
  Requires permission `visits:visit:execute`.
  
  Removes one of the signed-in rep's remaining stops for today that has not been checked in. The stop is cancelled and disappears from the rep's list. Requires permission to run visits.
  """
  cancelVisit(
    """The ID of the visit."""
    visitId: ID!
  ): Visit!
  """
  Requires a customer (portal or buyer app) session.
  
  Buyer 'change delivery address': swap the order's ship-to (and bill-to, mirroring placement) for another ACTIVE address of the same company. Same gates as updateMobileOrderItems; never on an order placed for a branch, nor on one whose delivery fee was a live courier quote for its address.
  """
  changeMobileOrderAddress(
    """The fields of the mobile order address to change."""
    input: ChangeMobileOrderAddressInput!
  ): MobileOrder!
  """
  Requires a customer (portal or buyer app) session.
  
  Buyer 'change payment method': switch how this order will be paid — COD, EFT, Online, or On-account (gated by the org's Organization.creditLimitEnabled + the customer's available credit, same check checkout uses). A SEPARATE gate from item/address edits: allowed even on an ONLINE order while unpaid, since that is exactly the case a buyer needs to switch OFF of. Refused if the new method would need to move the order's status BACKWARD from CONFIRMED to AWAITING_PAYMENT (a deliberately guarded status-transition invariant).
  """
  changeMobileOrderPaymentMethod(
    """The fields of the mobile order payment method to change."""
    input: ChangeMobileOrderPaymentMethodInput!
  ): MobileOrder!
  """
  Requires permission `sales:sales_order:ship`.
  
  Change the courier on an order before it is invoiced. The server re-rates the order and takes the chosen service's price itself; the client never sends an amount.
  """
  changeOrderCourier(
    """The order and the courier service to use."""
    input: ChangeOrderCourierInput!
  ): SalesOrder!
  """
  Requires an authenticated session.
  
  Changes the signed-in user's password. A user who already has a password must give the current one; a user without one, for example after an OTP or SSO sign-up, sets one. Every other session of the user ends and the current one stays.
  """
  changePassword(
    """The current password, when the user has one, and the new password."""
    input: ChangePasswordInput!
  ): User!
  """
  Public: no authentication required.
  
  Email-entry existence probe: routes the portal login screen to OTP-request (exists) or registration (not exists). Boolean-only — never leaks account status.
  """
  checkCustomerExists(
    """The details of the check customer exists request."""
    input: CheckCustomerExistsInput!
  ): CustomerExistsResponse!
  """
  Public: no authentication required.
  
  Register-flow existence probe: true when ANY account (any type — customer, staff, vendor) already occupies this email in the org, so the registration form can warn immediately instead of after a doomed OTP round-trip. Deliberately broader/more revealing than checkCustomerExists (owner-directed tradeoff for the staff-email-collision case).
  """
  checkEmailInUse(
    """The details of the check customer exists request."""
    input: CheckCustomerExistsInput!
  ): CustomerExistsResponse!
  """
  Requires permission `visits:visit:execute`.
  
  Checks the signed-in rep in at a planned visit, with an optional location. An offline replay can send the time the rep tapped and an idempotency key, so the check-in is created exactly once. If an admin cancelled or completed the visit meanwhile, the check-in is still recorded but the status is left unchanged. Requires permission to run visits.
  """
  checkInVisit(
    """
    When the rep tapped check-in, for an offline replay. The server limits it to a sensible time.
    """
    clientCheckInAt: DateTime
    """A key that makes an offline replay create the check-in only once."""
    idempotencyKey: String
    """The rep's latitude at check-in. Optional."""
    latitude: Float
    """The rep's longitude at check-in. Optional."""
    longitude: Float
    """The ID of the visit."""
    visitId: ID!
  ): Visit!
  """
  Requires permission `visits:visit:execute`.
  
  Checks the signed-in rep out of a visit, stamping the departure time and an optional location on the open check-in. A replay whose check-out already landed returns the current visit. Requires permission to run visits.
  """
  checkOutVisit(
    """
    When the rep tapped check-out, for an offline replay. It is never before the check-in.
    """
    clientCheckOutAt: DateTime
    """The rep's latitude at check-out. Optional."""
    latitude: Float
    """The rep's longitude at check-out. Optional."""
    longitude: Float
    """The ID of the visit."""
    visitId: ID!
  ): Visit!
  """
  Requires a customer (portal or buyer app) session.
  
  Removes every line from the cart and keeps its delivery directions. Pass the cart revision you last saw, and an operation ID so a retry applies once.
  """
  clearCart(
    """The expected cart revision and the operation ID. Both optional."""
    input: ClearCartInput
  ): CartType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Forget every fact Minori saved about the CALLER. Returns how many facts were live.
  """
  clearCopilotMemory: Int!
  """
  Requires permission `sales:sales_order:ship`.
  
  Remove the recorded courier payment from a shipment (recorded by mistake). Audited.
  """
  clearShipmentCourierPayment(
    """The ID of the shipment."""
    shipmentId: ID!
  ): ShipmentGql!
  """
  Requires permission `products:product:create`.
  
  Creates an independent copy of a product with its variants, quantity tiers, packs, tax settings and categories. The copy gets new SKUs and zero stock. Sending the same idempotency key again returns the original copy. Requires permission to create products.
  """
  cloneProduct(
    """
    The product to copy, an optional name and status for the copy, and the idempotency key.
    """
    input: CloneProductInput!
  ): Product!
  """
  Requires permission `settings:role:create`.
  
  Clone an existing role into a new one (permissions copied by default, user assignments on request)
  """
  cloneRole(
    """The details of the clone role request."""
    input: CloneRoleInput!
  ): Role!
  """
  Requires permission `sales:quote:update`.
  
  Close a quote: LOST moves it to REJECTED and records lossReason/competitorName/lossNotes/lostAt; WON records winReason/wonAt on an already ACCEPTED/CONVERTED quote (winning itself is conversion or the buyer's accept).
  """
  closeQuote(
    """The outcome, WON or LOST, and the reason."""
    input: CloseQuoteInput!
  ): Quote!
  """
  Requires permission `visits:visit:execute`.
  
  Completes a visit with its outcome and, when no order came of it, the reason. A visit that is already completed, cancelled or skipped is refused when completed online; an offline replay of an already completed visit returns it unchanged and does not overwrite its outcome. Requires permission to run visits.
  """
  completeVisit(
    """When the rep completed the visit, for an offline replay."""
    clientCompletedAt: DateTime
    """Why no order was taken. Optional."""
    noOrderReason: String
    """The result of the visit."""
    outcome: VisitOutcome!
    """The ID of the visit."""
    visitId: ID!
  ): Visit!
  """
  Requires permission `sales:quote:update`.
  
  Composes and sends a new email about a quote to every To and Cc address given. For now a new email must be tied to a quote: without one the call comes back unsuccessful with a message instead of sending. The result carries success, a message and the email's IDs. Requires permission to update quotes.
  """
  composeEmail(
    """
    The To and Cc addresses, subject, body, and the quote reference type and ID.
    """
    input: ComposeEmailInput!
  ): SendEmailResult!
  """
  Requires at least one of the permissions `payments:payment:update` or `purchase:payment:update`.
  
  Commits a DRAFT payment. A draft posts nothing and is excluded from the allocation pool; confirming it posts the partner balance once and sets the status from allocation coverage: none PENDING, part PARTIAL, all PAID. Confirming a payment that is already committed returns it unchanged, so a double click cannot post twice. Cancelled, reversed and refunded payments are refused.
  """
  confirmPayment(
    """The draft payment to confirm."""
    input: ConfirmPaymentInput!
  ): Payment!
  """
  Requires permission `sales:sales_order:confirm`.
  
  Confirm a DRAFT or AWAITING_PAYMENT order. With credit terms the customer's credit limit is checked, and unless negative stock is allowed the order is refused when on-hand stock cannot cover it. Send expectedVersion to guard against concurrent edits.
  """
  confirmSalesOrder(
    """
    The version of the record you last read. The change is refused if someone else changed it since.
    """
    expectedVersion: Int
    """The ID of the sales order."""
    id: ID!
  ): SalesOrder!
  """
  Requires the permissions `customers:customer:update` and `suppliers:supplier:create`.
  
  Adds the supplier role and a vendor account to a customer. Refused if the customer is already a vendor. Needs the customers update and suppliers create permissions.
  """
  convertCustomerToVendor(
    """The ID of the customer."""
    id: ID!
    """
    The vendor account details. Payment terms fall back to the organization's default when left out.
    """
    vendorData: ConvertToVendorInput!
  ): Customer!
  """
  Requires at least one of the permissions `customers:customer:update` or `suppliers:supplier:update`.
  
  Adds the customer role to a partner and creates its customer account with the organization's defaults. Needs the update permission for the partner's current roles and for the customer role.
  """
  convertPartnerToCustomer(
    """The ID of the partner."""
    id: ID!
  ): Partner!
  """
  Requires at least one of the permissions `customers:customer:update` or `suppliers:supplier:update`.
  
  Adds the supplier role to a partner and creates its supplier account with the organization's defaults. Needs the update permission for the partner's current roles and for the supplier role.
  """
  convertPartnerToSupplier(
    """The ID of the partner."""
    id: ID!
  ): Partner!
  """
  Requires permission `sales:sales_invoice:create`.
  
  Create an invoice directly from a quote. Lines keep the quoted prices. Taxed lines without a valid tax method are rejected, and the customer's credit limit is checked unless the caller can override it.
  """
  convertQuoteToInvoice(
    """The ID of the quote to invoice."""
    quoteId: ID!
  ): Invoice!
  """
  Requires permission `sales:sales_order:create`.
  
  Convert a quote into a sales order. Lines keep the quoted prices; any price drift is recorded rather than repriced. Taxed lines without a valid tax method are rejected. Send an idempotencyKey so a retry returns the original order instead of creating another. The quote moves to ACCEPTED and links to the order.
  """
  convertQuoteToSalesOrder(
    """
    A unique key you generate. Retrying with the same key returns the original result instead of creating another record.
    """
    idempotencyKey: String
    """The ID of the quote to convert."""
    quoteId: ID!
    """
    The ID of the warehouse that supplies the order, when it should differ from the quote's own.
    """
    warehouseId: ID
  ): SalesOrder!
  """
  Requires a customer (portal or buyer app) session.
  
  Adds a delivery or billing address to the signed-in customer's company.
  """
  createAddress(
    """
    The address: name, phone, lines, city, state, postal code, country, type and optional coordinates.
    """
    input: CreateMobileAddressInput!
  ): MobileAddress!
  """
  Requires permission `billing:ai_credit:purchase`.
  
  Creates a real Stripe (test-mode by config) checkout session for an AI-credit top-up.
  """
  createAiCreditCheckoutSession(
    """The details of the ai credit checkout to create."""
    input: CreateAiCreditCheckoutInput!
  ): AiCreditCheckoutSession!
  """
  Requires at least one of the permissions `settings:api:create` or `settings:tenant:update`.
  
  Generate a new API key. The full key is only shown once. Requires permission to create API keys or update tenant settings.
  """
  createApiKey(
    """The details of the api key to create."""
    input: CreateApiKeyInputGql!
  ): ApiKeyResult!
  """
  Requires permission `payments:bank-account:create`.
  
  Adds a bank account to the organization. The account number must be unique within the organization. The first account in a currency becomes that currency's default, and an account flagged as default takes over from the others in the same currency. Requires permission to create bank accounts.
  """
  createBankAccount(
    """
    The account name, number, bank name, currency and optional branch code, SWIFT code, IBAN, type, notes and default flag.
    """
    input: CreateBankAccountInput!
  ): BankAccount!
  """
  Requires permission `products:brand:create`.
  
  Creates a brand. The brand code must be unique within your organization, otherwise the request is refused. Needs the brands create permission.
  """
  createBrand(
    """The details of the brand to create."""
    createBrandInput: CreateBrandInput!
  ): Brand!
  """
  Requires permission `categories:category:create`.
  
  Creates a category. The code must not be used by another active category, and a parent, when given, must exist. The level and path follow from the parent. Requires permission to create categories.
  """
  createCategory(
    """The details of the category to create."""
    input: CreateCategoryInput!
  ): Category!
  """
  Requires an authenticated session.
  
  Creates a team chat channel, public or private. The creator is added as the channel's admin. Only admins and managers can create channels. Needs a signed-in user.
  """
  createChatChannel(
    """
    The channel's name and optional description, and whether it is private or the default channel.
    """
    input: CreateChannelInput!
  ): ChatChannel!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:delegation:manage`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve` or `purchase:purchase_order:approve`.
  
  Sets a cover: for the window given, the cover may decide approval requests needing the listed permissions on behalf of the person covered, never beyond what that person still holds, and never a request either of them raised. Covering for someone other than yourself needs approvals:delegation:manage.
  """
  createControlApprovalDelegation(
    """The cover to set."""
    input: CreateControlApprovalDelegationInput!
  ): ControlApprovalDelegation!
  """
  Requires an authenticated session.
  
  Starts a team chat conversation for the signed-in user, with an optional title. Needs a signed-in user.
  """
  createConversation(
    """The optional title of the conversation."""
    input: CreateConversationInput!
  ): ChatConversation!
  """
  Requires permission `catalog:copilot:chat`.
  
  Starts a new copilot chat for the signed-in user. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  createCopilotSession: CopilotSession!
  """
  Requires permission `sales:credit_note:create`.
  
  Creates a credit note for a customer, optionally against a sales invoice or a return. It starts as PENDING. A note against an invoice takes that invoice's currency and exchange rate; a standalone note uses the organization's base currency. The server works out the note's money from its lines, and the amount credited across an invoice's notes cannot exceed the invoice; see `invoiceCreditHeadroom`.
  """
  createCreditNote(
    """The details of the credit note to create."""
    input: CreateCreditNoteInput!
  ): CreditNote!
  """
  Requires at least one of the permissions `settings:currency:create` or `settings:tenant:update`.
  
  Adds a currency to the organization, creating the platform-wide currency record first when it does not exist. A currency already in the organization is refused. The first currency, or one flagged as base, becomes the base currency. Requires permission to create currencies or update tenant settings.
  """
  createCurrency(
    """The currency code and whether it is the base currency."""
    input: CreateCurrencyInput!
  ): Currency!
  """
  Requires permission `customers:customer:create`.
  
  Creates a customer in your organization, with its account, addresses and contacts. Needs the customers create permission.
  """
  createCustomer(
    """
    The customer to create: its name, account settings, addresses and contacts.
    """
    createCustomerInput: CreateCustomerInput!
  ): Customer!
  """
  Requires permission `payments:collection:create`.
  
  Records money received from a customer, optionally allocating it to invoices. The collection date must be valid, and an idempotency key makes a retry safe. Requires permission to create collections.
  """
  createCustomerCollection(
    """
    The customer, date, method, currency and amount, with optional exchange rate, bank account, reference, notes, allocations and idempotency key.
    """
    input: CreateCustomerCollectionInput!
  ): Payment!
  """
  Requires permission `purchase:debit_note:create`.
  
  Creates a debit note for a supplier, optionally against a purchase invoice or a return. A note raised from a return must be for the same supplier as the return and takes the return's figures; a standalone note carries the figures you enter, as a reviewed correction. The amount debited across an invoice's notes cannot exceed the invoice; see `invoiceDebitHeadroom`. Needs the debit notes feature on your plan.
  """
  createDebitNote(
    """The details of the debit note to create."""
    input: CreateDebitNoteInput!
  ): DebitNoteResponse!
  """
  Requires permission `products:discount:create`.
  
  Creates a discount scheme with its rules and validity window. The discount type, a percentage or a fixed amount, comes from the first discount rule. Needs the discounts create permission.
  """
  createDiscountScheme(
    """
    The scheme's name, optional code, scope, currency, validity dates, usage limits, discount rules, and applicable customer types and regions.
    """
    data: CreateDiscountSchemeDto!
  ): DiscountScheme!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Creates the organization's email configuration: provider, SMTP settings, sender name and address, and which reports and alerts to send. An organization has one, so creating a second is refused. Passwords and keys are stored encrypted. Requires permission to update email settings.
  """
  createEmailConfig(
    """
    The provider, SMTP or API credentials, sender details and reporting options.
    """
    input: CreateEmailConfigInput!
  ): EmailConfig!
  """
  Requires permission `purchase:grn:create`.
  
  Records goods received from a supplier into a warehouse, optionally against a purchase order. The supplier, warehouse, purchase order and every variant must exist, and the GRN's currency must match its purchase order's. Each line records accepted and rejected quantities: stock is posted for the accepted units only, at the line's unit cost, and the purchase order's received quantities are reconciled. Needs the goods receipt (GRN) feature on your plan.
  """
  createGRN(
    """The goods receipt note to create."""
    createGRNInput: CreateGRNInput!
  ): GRN!
  """
  Requires permission `settings:integration:create`.
  
  Sets up an integration for a service. The configuration must be valid for that service, and a service can only be set up once. When it is created switched on, it is validated straight away. Requires permission to create integrations.
  """
  createIntegrationSetting(
    """
    The service, its configuration and credentials, and whether it is switched on.
    """
    input: CreateIntegrationSettingInput!
  ): IntegrationSetting!
  """
  Requires permission `inventory:stock_transfer:create`.
  
  Always refuses: internal returns are not supported. To move stock between warehouses, use a stock transfer.
  """
  createInternalReturn(
    """The details of the internal return to create."""
    input: CreateInternalReturnInput!
  ): ReturnResponse! @deprecated(reason: "Internal returns are not supported; move stock between warehouses with a stock transfer (transferInventory).")
  """
  Requires at least one of the permissions `payments:invoice:create` or `purchase:purchase_invoice:create`.
  
  Creates an invoice for a customer (sales invoice) or a supplier (purchase invoice). The partner must exist and at least one line is required. A line can bill a sales order line, and the quantity billed cannot exceed what that order line still has to invoice. An invoice with no linked order is checked against the customer's or supplier's credit limit; an order-linked invoice is not, because its order was already checked. New invoices use the tax-exclusive method. The server calculates every total. A sales invoice needs the invoices create permission; a purchase invoice needs the purchase invoices create permission.
  """
  createInvoice(
    """The invoice to create."""
    input: CreateInvoiceInput!
  ): Invoice!
  """
  Requires permission `platform:language:manage`.
  
  Creates a language record. Languages are shared by every organization, so this needs the platform permission to manage languages, which only platform administrators hold.
  """
  createLanguage(
    """The language's code, name and text direction."""
    data: CreateLanguageInput!
  ): Language!
  """
  Requires permission `settings:appearance:create`.
  
  Creates a menu. A parent, when given, must exist and must be a main menu. Needs the appearance settings create permission.
  """
  createMenu(
    """
    The menu's name, label, path, order, type and optional parent, icon, description and required permissions.
    """
    input: CreateMenuInput!
  ): Menu!
  """
  Requires an authenticated session.
  
  Posts a message to a conversation the caller has access to, and delivers it live to the people who can see that conversation. Needs a signed-in user.
  """
  createMessage(
    """The conversation, the sender role, the text and optional metadata."""
    input: CreateMessageInput!
  ): ChatMessage!
  """
  Requires at least one of the permissions `products:tax:update` or `settings:tenant:update`.
  
  Creates or updates the organization's tax configuration, including its default sales and purchase tax groups. Needs the tax update permission, or the tenant settings update permission.
  """
  createOrUpdateOrganizationTaxConfig(
    """The tax configuration, including the default tax groups."""
    input: CreateOrganizationTaxConfigurationInput!
  ): OrganizationTaxConfiguration!
  """
  Requires at least one of the permissions `purchase:debit_note:create` or `sales:credit_note:create`.
  
  Creates a follow-on return for part of an existing return, naming the parent return and the lines and quantities to return. The parent return must exist. Needs the create permission of the parent return's direction (credit notes for a customer return, debit notes for a supplier return).
  """
  createPartialReturn(
    """The items and quantities to move into the new return."""
    items: [PartialReturnItemInput!]!
    """The ID of the return to split."""
    parentReturnId: String!
  ): ReturnResponse!
  """
  Requires at least one of the permissions `customers:customer:create` or `suppliers:supplier:create`.
  
  Creates a customer or supplier in your organization. The permission needed follows the roles the new partner carries: customers create for a customer, suppliers create for a supplier.
  """
  createPartner(
    """The partner to create, including its roles."""
    createPartnerInput: CreatePartnerInput!
  ): Partner!
  """
  Requires at least one of the permissions `payments:collection:create`, `payments:payment:create` or `purchase:payment:create`.
  
  Records a payment: money received from a customer (`type` COLLECTION) or paid to a supplier (`type` PAYMENT), optionally allocated to invoices in the same call. You need the permission that matches the `type` you send: collections create for COLLECTION, supplier payments create (purchase) for PAYMENT. An explicit idempotency key makes a retry return the original payment, and the same key with a different request is rejected. Allocations must be in the payment's currency and cannot exceed an invoice's outstanding amount.
  """
  createPayment(
    """The payment to record."""
    input: CreatePaymentInput!
  ): Payment!
  """
  Requires a customer (portal or buyer app) session.
  
  Start an online payment checkout. Creates an AWAITING_PAYMENT order (or reuses an existing one on retry) and returns the hosted checkout URL.
  """
  createPaymentCheckout(
    """The details of the payment checkout to create."""
    input: CreatePaymentCheckoutInput!
  ): MobilePaymentCheckout!
  """
  Requires at least one of the permissions `settings:sales:create` or `settings:tenant:update`.
  
  Creates a payment term, such as net 30, for the organization. The term code is yours to choose and is checked for validity. A term cannot be created as the default while it is inactive.
  """
  createPaymentTerm(
    """The payment term to create."""
    input: CreatePaymentTermInput!
  ): PaymentTerm!
  """
  Requires permission `products:product:create`.
  
  Creates a product with its variants. Setting opening stock needs the permission to adjust stock. Requires permission to create products.
  """
  createProduct(
    """The details of the product and its variants."""
    input: CreateProductInput!
  ): Product!
  """
  Requires permission `products:product:update`.
  
  Adds a product attribute, with any first values, before any product carries it. Requires permission to update products.
  """
  createProductAttribute(
    """The new attribute."""
    input: CreateProductAttributeInput!
  ): ProductAttributeChangeResult!
  """
  Requires permission `products:import:stage`.
  
  Requests a presigned upload URL and creates the UPLOADED import ledger row. No file bytes cross GraphQL.
  """
  createProductImport(
    """The details of the product import to create."""
    input: CreateProductImportInput!
  ): CreateProductImportResult!
  """
  Requires permission `products:product:create`.
  
  Adds a variant to a product. The SKU must not already be in use. Setting opening stock needs the permission to adjust stock. Requires permission to create products.
  """
  createProductVariant(
    """The details of the variant to create."""
    createProductVariantInput: CreateProductVariantInput!
    """The ID of the product to add the variant to."""
    productId: ID!
  ): ProductVariant!
  """
  Requires permission `purchase:purchase_order:create`.
  
  Creates a purchase order for a supplier. The organization must have a base currency configured and every line needs a variant. The order is dated today unless you hold the permission to backdate it, and a payment term is checked when you enter it. Needs the purchase orders feature on your plan.
  """
  createPurchaseOrder(
    """The details of the purchase order to create."""
    input: CreatePurchaseOrderInput!
  ): PurchaseOrder!
  """
  Requires permission `purchase:debit_note:create`.
  
  Starts a return of goods to a supplier, against a goods receipt (GRN) or a purchase order. The supplier must exist with the supplier role, the document and products must exist, and a unit cost must be resolvable for each line. Needs the purchase returns feature on your plan and the debit notes create permission; a return that does not wait for approval (`requiresApproval` false) is approved as it is created and also needs the debit notes approve permission.
  """
  createPurchaseReturn(
    """The details of the purchase return to create."""
    input: CreatePurchaseReturnInput!
  ): ReturnResponse!
  """
  Requires permission `sales:quote:create`.
  
  Create a quote for a customer. Line prices come from the quote input, so send each line's unitPrice. Counts against the organization's monthly quote limit. New quotes start as DRAFT unless a status is supplied.
  """
  createQuote(
    """The quote to create."""
    input: CreateQuoteInput!
  ): Quote!
  """
  Requires permission `platform:region:manage`.
  
  Creates a region. Regions are shared by every organization, so this needs the platform permission to manage regions, which only platform administrators hold.
  """
  createRegion(
    """The region's details."""
    input: CreateRegionInput!
  ): Region!
  """
  Requires permission `sales:credit_note:create`.
  
  Not implemented yet: this call is refused with an error and creates nothing. Repair orders cannot be recorded. Needs the credit notes create permission.
  """
  createRepairOrder(
    """The return items to repair."""
    items: [PartialReturnItemInput!]!
    """The ID of the return."""
    returnId: String!
  ): ReturnActionResult!
  """
  Requires permission `sales:credit_note:create`.
  
  Records a return against a sales order (`type` SALES_RETURN, goods coming back from a customer) or a purchase order (`type` PURCHASE_RETURN, goods going back to a supplier). The return starts as PENDING and moves no stock until `processReturn`. A sales return needs an order whose goods have gone out: orders that are DRAFT, AWAITING_PAYMENT, CONFIRMED or CANCELLED are refused. Each line must name a variant and resolve to one line of the source order, and the quantity returned across all returns of that line cannot exceed what was ordered (sales) or received (purchase). The refund value comes from the original order line, not from a price you send. A purchase return needs the purchase returns feature on your plan and the debit note create permission as well.
  """
  createReturn(
    """The details of the return to create."""
    input: CreateReturnInput!
  ): ProductReturn!
  """
  Requires permission `settings:role:create`.
  
  Creates a role in your organization. Refused if the name belongs to a soft-deleted role; the error then carries the details so a client can offer to restore that role instead. Needs settings:role:create.
  """
  createRole(
    """The new role's name and settings."""
    input: CreateRoleInput!
  ): Role!
  """
  Requires permission `products:product:update`.
  
  Creates a SKU pattern, optionally scoped to a brand or category. Any brand or category named must belong to the organization. Needs the products update permission.
  """
  createSKUPattern(
    """
    The pattern's name, pattern text, priority, sequence length, optional brand and category, and active state.
    """
    createSKUPatternInput: CreateSKUPatternInput!
  ): SKUPattern!
  """
  Requires permission `sales:sales_order:create`.
  
  Create a sales order. Line unitPrice is optional because the server prices each line; the order starts as DRAFT unless you send CONFIRMED or AWAITING_PAYMENT. Taxed lines need a valid tax method. Needs the sales order create permission, and the sales order confirm permission when status is CONFIRMED.
  """
  createSalesOrder(
    """The order to create."""
    input: CreateSalesOrderInput!
  ): SalesOrder!
  """
  Requires the permissions `sales:credit_note:approve` and `sales:credit_note:create`.
  
  Starts a return request (RMA) for a customer against a sales invoice. The invoice must exist, every product returned must be on it, and the invoice must be no more than 30 days old unless the request is marked as a customer request. This is the invoice-based flow; the order-based flow is `createReturn`, and a return created in one flow cannot be advanced by the other. The return is approved as it is created, so it needs the credit notes create and approve permissions, and the customer must be one you may see.
  """
  createSalesReturn(
    """The details of the sales return to create."""
    input: CreateSalesReturnInput!
  ): ReturnResponse!
  """
  Requires permission `marketing:link:write`.
  
  Creates a short link to a web address. The address must be valid, and a custom alias, when given, must not be taken. The link can have a title, description, tags and an expiry. Needs the marketing link write permission.
  """
  createShortUrl(
    """
    The original URL and optionally a custom alias, title, description, tags and expiry.
    """
    input: CreateShortUrlInput!
  ): ShortUrlEntity!
  """
  Requires permission `inventory:stock_movement:create`.
  
  Records one stock movement and changes stock by its quantity. An issue must be negative and a receipt positive, and a movement of the wrong sign is refused; transfers, adjustments, returns and cycle counts carry their own sign. Which warehouse is affected depends on the type, and the movement needs one. A quantity entered in a pack unit is converted to base units. Needs the stock movement create permission.
  """
  createStockMovement(
    """
    The movement type, warehouses, product, variant, quantity and optional batch, serial number, reference, reason, notes and unit.
    """
    input: CreateStockMovementInput!
  ): StockMovement!
  """
  Requires permission `purchase:payment:create`.
  
  Records a payment to a supplier (`type` PAYMENT), optionally allocated to the supplier's purchase invoices in the same call. Allocations must be in the payment's currency and cannot exceed an invoice's outstanding amount. An explicit idempotency key makes a retry return the original payment. Needs the supplier payments create permission.
  """
  createSupplierPayment(
    """The supplier payment to record."""
    input: CreateSupplierPaymentInput!
  ): Payment!
  """
  Requires permission `products:tax:create`.
  
  Creates a tax group from existing tax rates. Every rate listed must exist, and the code must not be used by another tax group. Needs the tax create permission.
  """
  createTaxGroup(
    """The tax group's name, code and the tax rates it holds."""
    input: CreateTaxGroupInput!
  ): TaxGroup!
  """
  Requires permission `products:tax:create`.
  
  Creates a tax rate. The code must not be used by another active tax rate; a clash is refused and names the rate that uses it. Needs the tax create permission.
  """
  createTaxRate(
    """The tax rate's name, code, rate and where it applies."""
    input: CreateTaxRateInput!
  ): TaxRate!
  """
  Requires at least one of the permissions `settings:currency:update` or `settings:tenant:update`.
  
  Adds an exchange rate of the organization's own, with a start date and an optional stop date, in the organization's time zone. It only decides what later documents default to: existing documents keep the rate they were created with, and no price is ever produced by converting currency. Requires permission to update currency or tenant settings.
  """
  createTenantExchangeRate(
    """
    The currency, the rate, the start date, an optional stop date and a note.
    """
    input: CreateTenantExchangeRateInput!
  ): TenantExchangeRate!
  """
  Requires permission `settings:tenant:create`.
  
  Creates a setting in a category the generic settings operations manage. A category that has its own update operation is refused. Needs settings:tenant:create.
  """
  createTenantSetting(
    """
    The setting's category, key, value and data type, with an optional description, validation rule and active flag.
    """
    input: CreateTenantSettingInput!
  ): TenantSetting!
  """
  Requires at least one of the permissions `settings:regional:create` or `settings:tenant:update`.
  
  Adds a timezone with its code, name and UTC offset. The code must not already be used in the organization. A timezone flagged as default takes over from the current default. Requires permission to create regional settings or update tenant settings.
  """
  createTimezone(
    """
    The timezone's code, name, UTC offset and optional daylight-saving rules, sort order and default flag.
    """
    createTimezoneInput: CreateTimezoneInput!
  ): Timezone!
  """
  Requires permission `products:product:create`.
  
  Create a unit of measure. The code must be unique in the organization, ignoring case. A COUNT unit must have 0 decimal places and cannot allow fractions. Marking the unit as base clears the base flag from the category's current base unit. Needs the products create permission.
  """
  createUOM(
    """The unit to create."""
    data: CreateUOMInput!
  ): UnitOfMeasure!
  """
  Requires permission `products:product:update`.
  
  Define how one unit converts to another. Both units must exist and be in the same category, and no conversion may already exist between them in either direction. The reverse conversion is created automatically. Needs the products update permission.
  """
  createUOMConversion(
    """The conversion to create."""
    data: CreateUOMConversionInput!
  ): UOMConversion!
  """
  Requires permission `users:user:create`.
  
  Creates a user in your organization. The organization always comes from the signed-in user, never from the input. Naming a role also needs the role update permission. Needs users:user:create.
  """
  createUser(
    """The new user's details. Any organization in the input is ignored."""
    input: CreateUserInput!
  ): User!
  """
  Requires permission `suppliers:supplier:update`.
  
  Links a supplier to a product variant with the supplier's own SKU, cost, order limits and lead time. The supplier and the variant must exist, and one mapping per supplier and variant is allowed. Needs the suppliers update permission.
  """
  createVendorProduct(
    """
    The supplier, product, variant and supplier SKU, with optional cost, order limits, lead time, ratings and notes.
    """
    createVendorProductInput: CreateVendorProductInput!
  ): VendorProduct!
  """
  Requires permission `inventory:warehouse:create`.
  
  Creates a warehouse. The code must not already be used by another warehouse of the organization. A new warehouse is active. Needs the warehouse create permission.
  """
  createWarehouse(
    """The warehouse's name, code and details."""
    input: CreateWarehouseInput!
  ): Warehouse!
  """
  Requires the permissions `sales:credit_note:approve` and `sales:credit_note:create`.
  
  Starts a warranty return against a sales invoice. The invoice and each product must exist on it, and the product's warranty must still be valid, otherwise the line is refused. The return is approved as it is created, so it needs the credit notes create and approve permissions, and the customer must be one you may see.
  """
  createWarrantyReturn(
    """The details of the warranty return to create."""
    input: CreateWarrantyReturnInput!
  ): ReturnResponse!
  """
  Requires permission `settings:webhooks:create`.
  
  Creates a webhook endpoint with a name, a receiver URL and the events it subscribes to. The URL must use https in production, and at least one known event type is required. The response carries the signing secret, and it is the only time besides rotateWebhookEndpointSecret that the secret is returned, so store it. Requires permission to create webhooks.
  """
  createWebhookEndpoint(
    """
    The endpoint's name, receiver URL, subscribed event types and whether it is active.
    """
    input: WebhookEndpointInput!
  ): WebhookEndpointWithSecret!
  """
  Requires permission `settings:integration:update`.
  
  Submits a new message template, with optional header, footer and buttons, to the WhatsApp provider for approval. Requires permission to update integrations.
  """
  createWhatsAppTemplate(
    """
    The template's name, language, category, header, body, footer and buttons.
    """
    input: CreateWhatsAppTemplateInput!
    """
    The WhatsApp provider to use. Omit it to use the organization's enabled provider, else its most recently edited one.
    """
    provider: WhatsAppProvider
  ): WhatsAppCreateTemplateResultGql!
  """
  Requires a customer (portal or buyer app) session.
  
  Accept a quote: marks ACCEPTED + notifies the seller. Optional poNumber is stored as the quote reference and becomes the order's customerPoNumber on conversion. The order itself is placed via customerPlaceOrderFromQuote or by staff. Errors: QUOTE_NOT_ACCEPTABLE, QUOTE_EXPIRED, QUOTE_VERSION_CONFLICT, PO_NUMBER_TOO_LONG. screen 13.
  """
  customerAcceptQuote(
    """
    The version of the quote you last read. The change is refused if someone else changed it since.
    """
    expectedVersion: Int
    """
    Buyer's PO number, persisted to Quote.reference → SalesOrder.customerPoNumber.
    """
    poNumber: String
    """The ID of the quote."""
    quoteId: ID!
  ): CustomerQuoteDetail!
  """
  Requires a customer (portal or buyer app) session.
  
  Re-activate a deactivated teammate (CUSTOMER_ADMIN only) — the undo for customerDeactivateTeamMember. Idempotent on an already-active member.
  """
  customerActivateTeamMember(
    """The ID of the user."""
    userId: ID!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Add/merge a line on a buying list. screen 12.
  """
  customerAddBuyingListItem(
    """The details of the customer add buying list item request."""
    input: CustomerAddBuyingListItemInput!
  ): CustomerBuyingListView!
  """
  Requires a customer (portal or buyer app) session.
  
  Merge a whole buying list into the shared cart via the CustomerCartService public API (repriced server-side). screen 12.
  """
  customerAddListToCart(
    """The ID of the buying list."""
    listId: ID!
  ): CartType!
  """
  Requires a customer (portal or buyer app) session.
  
  Approve a pending request: replays the cart snapshot through the canonical checkout path (fresh reprice) and returns the created order. Errors: APPROVAL_NOT_PENDING, NOT_AN_APPROVER, OVER_CREDIT_LIMIT. screen 14.
  """
  customerApproveOrderRequest(
    """The ID of the approval request."""
    requestId: ID!
  ): CustomerApprovalDecisionResult!
  """
  Requires a customer (portal or buyer app) session.
  
  Cancel one of the buyer's own sales orders (reason optional). Delegates to OrdersService.cancelSalesOrder — the same invoice/status-transition guards as the admin app's cancel action.
  """
  customerCancelOrder(
    """The ID of the order."""
    orderId: ID!
    """Why the order is cancelled."""
    reason: String
  ): CustomerOrderDetail!
  """
  Requires a customer (portal or buyer app) session.
  
  Cancel one of the buyer's own quotes (reason optional). Delegates to QuotesService.update({status: 'CANCELLED'}) — the same transition/converted-quote guards as the admin app's Cancel Quote action.
  """
  customerCancelQuote(
    """The ID of the quote."""
    quoteId: ID!
    """Why the quote is being cancelled."""
    reason: String
  ): CustomerQuoteDetail!
  """
  Requires a customer (portal or buyer app) session.
  
  Add a partner delivery address (partner-scoped Address row, mirrors mobile-bff). screen 17.
  """
  customerCreateAddress(
    """The details of the customer address request."""
    input: CustomerAddressInput!
  ): CustomerAddress!
  """
  Requires a customer (portal or buyer app) session.
  
  Create an empty buying list. screen 12.
  """
  customerCreateBuyingList(
    """The details of the customer create buying list request."""
    input: CustomerCreateBuyingListInput!
  ): CustomerBuyingListView!
  """
  Requires a customer (portal or buyer app) session.
  
  Snapshot the current cart's lines into a new buying list (quantities only, no prices). screen 12.
  """
  customerCreateBuyingListFromCart(
    """The details of the customer create buying list request."""
    input: CustomerCreateBuyingListInput!
  ): CustomerBuyingListView!
  """
  Requires a customer (portal or buyer app) session.
  
  Request a return (RMA) against a delivered order. Errors: RETURN_WINDOW_EXPIRED, ITEM_NOT_ON_ORDER. screen 15.
  """
  customerCreateReturn(
    """The details of the customer create return request."""
    input: CustomerCreateReturnInput!
  ): CustomerReturnView!
  """
  Requires a customer (portal or buyer app) session.
  
  Deactivate a teammate (CUSTOMER_ADMIN only). The last active CUSTOMER_ADMIN is protected (LAST_OWNER_PROTECTED). screen 16.
  """
  customerDeactivateTeamMember(
    """The ID of the user."""
    userId: ID!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Decline a pending request with an optional reason. Errors: APPROVAL_NOT_PENDING, NOT_AN_APPROVER. screen 14.
  """
  customerDeclineOrderRequest(
    """Why the request is declined."""
    reason: String
    """The ID of the approval request."""
    requestId: ID!
  ): CustomerApprovalDecisionResult!
  """
  Requires a customer (portal or buyer app) session.
  
  Remove a partner address. screen 17.
  """
  customerDeleteAddress(
    """The ID of the address."""
    addressId: ID!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Soft-delete a buying list. screen 12.
  """
  customerDeleteBuyingList(
    """The ID of the buying list."""
    listId: ID!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Invite a teammate (CUSTOMER_ADMIN only). Roles reuse CUSTOMER_* UserRole members. screen 16.
  """
  customerInviteTeamMember(
    """The details of the customer invite team member request."""
    input: CustomerInviteTeamMemberInput!
  ): CustomerTeamMember!
  """
  Requires a customer (portal or buyer app) session.
  
  Ends a customer's session so its tokens stop working.
  """
  customerLogout(
    """The session to end."""
    sessionToken: String
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Place a sales order from one of THIS partner's ACCEPTED quotes. Runs the staff convertToSalesOrder path unchanged (quoted prices honoured, drift audit, order born DRAFT). Errors: QUOTE_NOT_ACCEPTED, QUOTE_ALREADY_ORDERED, QUOTE_VERSION_CONFLICT, FORBIDDEN_ROLE.
  """
  customerPlaceOrderFromQuote(
    """
    The version of the quote you last read. The change is refused if someone else changed it since.
    """
    expectedVersion: Int
    """The ID of the quote."""
    quoteId: ID!
  ): CustomerPlaceOrderResult!
  """
  Public: no authentication required.
  
  Exchanges a customer's refresh token for a new access token. Needs no sign-in.
  """
  customerRefreshToken(
    """The refresh token to exchange."""
    input: CustomerRefreshTokenInput!
  ): CustomerAuthResponse!
  """
  Requires a customer (portal or buyer app) session.
  
  Register a buyer EFT transfer against an order or invoice (exactly one of orderId | invoiceId). Creates a PENDING COLLECTION payment — the "Payment under review" overlay. Errors: EFT_AMOUNT_EXCEEDS_OUTSTANDING. screens 9/10.
  """
  customerRegisterEftPayment(
    """The details of the customer register eft payment request."""
    input: CustomerRegisterEftPaymentInput!
  ): CustomerEftPaymentResult!
  """
  Requires a customer (portal or buyer app) session.
  
  Remove a line from a buying list. screen 12.
  """
  customerRemoveBuyingListItem(
    """The ID of the list item."""
    itemId: ID!
    """The ID of the buying list."""
    listId: ID!
  ): CustomerBuyingListView!
  """
  Requires a customer (portal or buyer app) session.
  
  Merge every line of a past order into the shared cart via the CustomerCartService public API (repriced server-side). screen 6/8.
  """
  customerReorderFromOrder(
    """The ID of the order."""
    orderId: ID!
  ): CartType!
  """
  Requires a customer (portal or buyer app) session.
  
  Turn the current cart into a quote request (QT-…, validity = PortalConfiguration.quoteValidityDays; server repriced). Honoured only when allowQuoteRequests is on. screen 13.
  """
  customerRequestQuoteFromCart(
    """The details of the quote request."""
    input: CustomerRequestQuoteInput!
  ): CustomerQuoteRequestResult!
  """
  Requires a customer (portal or buyer app) session.
  
  Mark an address as the ordering default. screen 17.
  """
  customerSetDefaultAddress(
    """The ID of the address."""
    addressId: ID!
  ): CustomerAddress!
  """
  Requires a customer (portal or buyer app) session.
  
  Update a partner address. screen 17.
  """
  customerUpdateAddress(
    """The ID of the address."""
    addressId: ID!
    """The details of the customer address request."""
    input: CustomerAddressInput!
  ): CustomerAddress!
  """
  Requires a customer (portal or buyer app) session.
  
  Set a line's quantity and/or pack. Separate from customerAddBuyingListItem, which MERGES by bumping the quantity — an edit must set it. screen 12.
  """
  customerUpdateBuyingListItem(
    """The details of the customer update buying list item request."""
    input: CustomerUpdateBuyingListItemInput!
  ): CustomerBuyingListView!
  """
  Requires a customer (portal or buyer app) session.
  
  Update a teammate's role/order-limit/approver flag (CUSTOMER_ADMIN only). screen 16.
  """
  customerUpdateTeamMember(
    """The details of the customer update team member request."""
    input: CustomerUpdateTeamMemberInput!
  ): CustomerTeamMember!
  """
  Requires a customer (portal or buyer app) session.
  
  Write MANY buying lists in a SINGLE round trip — the batch form of customerAddBuyingListItem/customerRemoveBuyingListItem. Grouped by list so ONE call covers both axes the app needs: many variants into one list, and one variant across many lists, adds and removes together. Returns every touched list in full plus a per-line ok/error, so one bad line does not discard the rest. screen 12.
  """
  customerWriteBuyingLists(
    """The details of the customer write buying lists request."""
    input: CustomerWriteBuyingListsInput!
  ): CustomerBuyingListsWriteView!
  """
  Requires at least one of the permissions `settings:currency:update` or `settings:tenant:update`.
  
  Turns a currency off for the organization only. The base currency cannot be deactivated; set another as base first. Requires permission to update currency or tenant settings.
  """
  deactivateCurrency(
    """The ID of the currency."""
    id: String!
  ): Currency!
  """
  Requires a tenant administrator.
  
  Sets a customer's status to inactive, which is also how a pending customer is rejected. Tenant admins only.
  """
  deactivateCustomer(
    """The ID of the customer."""
    id: ID!
  ): Customer!
  """
  Requires permission `customers:customer_user:delete`.
  
  Deactivates a customer user. Every sign-in route refuses them from then on, and their record stays. Needs customers:customer_user:delete.
  """
  deactivateCustomerUser(
    """The ID of the customer user."""
    userId: ID!
  ): Boolean!
  """
  Requires permission `products:discount:update`.
  
  Turns a discount scheme off, so it stops applying. Its rules and assignments are kept. Needs the permission to edit discounts.
  """
  deactivateDiscountScheme(
    """The ID of the discount scheme."""
    id: String!
  ): DiscountScheme!
  """
  Requires at least one of the permissions `settings:sales:delete` or `settings:tenant:update`.
  
  Deactivates a payment term. Inactive terms are left out of `paymentTerms` unless `includeInactive` is true. The current default cannot be deactivated: choose another default first.
  """
  deactivatePaymentTerm(
    """The ID of the payment term to deactivate."""
    id: ID!
  ): PaymentTerm!
  """
  Requires permission `payments:bank-account:delete`.
  
  Deletes a bank account. Needs the bank accounts delete permission.
  """
  deleteBankAccount(
    """The ID of the bank account."""
    id: ID!
  ): Boolean!
  """
  Requires permission `products:brand:delete`.
  
  Deletes a brand. A brand that still has products is refused; move or remove its products first. Needs the brands delete permission.
  """
  deleteBrand(
    """The ID of the brand."""
    id: ID!
  ): Brand!
  """
  Requires permission `categories:category:delete`.
  
  Deletes a category. A category that has subcategories or products is refused. Requires permission to delete categories.
  """
  deleteCategory(
    """The ID of the category."""
    id: String!
  ): Category!
  """
  Requires an authenticated session.
  
  Deletes a channel together with its conversation and messages. The default channel cannot be deleted. Only an admin or manager, or the channel's creator, can do this. Needs a signed-in user.
  """
  deleteChatChannel(
    """The ID of the chat channel."""
    id: String!
  ): DeleteResponse!
  """
  Requires permission `commissions:commission:delete`.
  
  Removes a role's commission rate. Fails if the role has no rate. Requires permission to delete commissions.
  """
  deleteCommissionRoleRate(
    """The role whose rate to remove."""
    role: String!
  ): Boolean!
  """
  Requires an authenticated session.
  
  Deletes a conversation. The caller must have access to it. Needs a signed-in user.
  """
  deleteConversation(
    """The ID of the conversation."""
    id: String!
  ): DeleteResponse!
  """
  Requires permission `settings:organization:update`.
  
  Deletes one playbook rule by its key and returns false when no live rule had that key. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to update organization settings.
  """
  deleteCopilotPlaybookRule(
    """The key of the playbook rule to delete."""
    key: String!
  ): Boolean!
  """
  Requires permission `settings:organization:update`.
  
  Delete a saved prompt, returning the organization's remaining list. Deleting one that is already gone is not an error.
  """
  deleteCopilotPromptTemplate(
    """The slug of the template."""
    slug: String!
  ): [CopilotPromptTemplateType!]!
  """
  Requires permission `catalog:copilot:chat`.
  
  Delete one of the CALLER'S OWN chats (soft delete: it leaves every list; its cards and run journal remain as the audit trail).
  """
  deleteCopilotSession(
    """The ID of the Copilot session."""
    id: ID!
  ): Boolean!
  """
  Requires permission `catalog:copilot:chat`.
  
  Deletes the saved import rules of one supplier and returns whether a rule was removed. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  deleteCopilotSupplierRule(
    """
    The supplier whose rules to delete. Matched without regard to case or punctuation.
    """
    supplierName: String!
  ): Boolean!
  """
  Requires permission `platform:currency:manage`.
  
  Deletes a currency's master record. Currencies are shared by every organization, so this needs the platform permission to manage currencies, which only platform administrators hold. To stop using a currency in one organization, deactivate it instead.
  """
  deleteCurrency(
    """The ID of the currency."""
    id: String!
  ): BooleanResponse!
  """
  Requires permission `settings:integration:delete`.
  
  Deletes a delivery partner configuration. The partner is switched off and its webhook URL stops working for good, and the same provider can be set up again later. Needs the delivery partners plan feature and permission to delete integrations.
  """
  deleteDeliveryPartnerConfig(
    """The ID of the delivery partner configuration."""
    id: ID!
  ): Boolean!
  """
  Requires permission `products:discount:delete`.
  
  Deletes a discount scheme together with its usage history and cascading rules. Needs the discounts delete permission.
  """
  deleteDiscountScheme(
    """The ID of the discount scheme."""
    id: String!
  ): Boolean!
  """
  Requires permission `sales:quote:update`.
  
  Permanently deletes one of the caller's own email drafts. Another user's draft, or an unknown ID, is treated as missing. Requires permission to update quotes.
  """
  deleteDraft(
    """The ID of the email draft."""
    id: ID!
  ): Boolean!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Deletes the organization's email configuration. Requires permission to update email settings.
  """
  deleteEmailConfig: Boolean!
  """
  Requires permission `products:import:stage`.
  
  S2.2 — soft-delete a mapping profile.
  """
  deleteImportMappingProfile(
    """The ID of the import mapping profile."""
    id: String!
  ): Boolean!
  """
  Requires permission `settings:integration:delete`.
  
  Deletes an integration and returns it. Fails if the integration does not exist. Requires permission to delete integrations.
  """
  deleteIntegrationSetting(
    """The ID of the integration."""
    id: String!
  ): IntegrationSetting!
  """
  Requires at least one of the permissions `payments:invoice:delete` or `purchase:purchase_invoice:delete`.
  
  Always refuses: invoices are cancelled, never deleted. Use `cancelInvoice`; the cancelled invoice is kept for audit. An invoice that already has payments is refused with a pointer to cancelling it. Needs the invoices delete or purchase invoices delete permission.
  """
  deleteInvoice(
    """The ID of the invoice."""
    id: ID!
  ): Invoice! @deprecated(reason: "Invoices are cancelled, never deleted — use cancelInvoice. This mutation always refuses.")
  """
  Requires permission `platform:language:manage`.
  
  Deletes a language record. Languages are shared by every organization, so this needs the platform permission to manage languages, which only platform administrators hold.
  """
  deleteLanguage(
    """The ID of the language."""
    id: String!
  ): Boolean!
  """
  Requires permission `settings:appearance:delete`.
  
  Deletes a menu, which hides it rather than erasing it. A menu that still has active submenus cannot be deleted. Needs the appearance settings delete permission.
  """
  deleteMenu(
    """The ID of the menu."""
    id: ID!
  ): Boolean!
  """
  Requires an authenticated session.
  
  Deletes one message. Only the owner of the conversation can delete its messages, and a message of another organization reads as missing. Needs a signed-in user.
  """
  deleteMessage(
    """The ID of the message."""
    id: String!
  ): DeleteResponse!
  """
  Requires at least one of the permissions `settings:sales:delete` or `settings:tenant:update`.
  
  Deletes a payment term: it leaves the settings list and every picker, and no new document can use it. Documents created before the delete keep the term, its label and their due dates. The code cannot be reused. The current default cannot be deleted: choose another default first.
  """
  deletePaymentTerm(
    """The ID of the payment term to delete."""
    id: ID!
  ): Boolean!
  """
  Requires permission `products:product:update`.
  
  Deletes a product attribute or one value of it; something products carry is removed from them only when asked. Requires permission to update products.
  """
  deleteProductAttribute(
    """What to delete."""
    input: DeleteProductAttributeInput!
  ): ProductAttributeChangeResult!
  """
  Requires permission `products:product:delete`.
  
  Deletes a variant. The last remaining variant of a product cannot be deleted. Requires permission to delete products.
  """
  deleteProductVariant(
    """The ID of the variant."""
    id: ID!
  ): ProductVariant!
  """
  Requires permission `platform:region:manage`.
  
  Deletes a region. Regions are shared by every organization, so this needs the platform permission to manage regions, which only platform administrators hold.
  """
  deleteRegion(
    """The ID of the region."""
    id: String!
  ): Region!
  """
  Requires permission `commissions:commission:delete`.
  
  Removes a sales rep's commission profile and rate. Requires permission to delete commissions.
  """
  deleteRepCommissionRate(
    """The ID of the sales rep."""
    userId: String!
  ): Boolean!
  """
  Requires permission `products:product:update`.
  
  Deletes a SKU pattern. SKUs already generated from it are not changed. Needs the products update permission.
  """
  deleteSKUPattern(
    """The ID of the SKU pattern."""
    id: ID!
  ): SKUPattern!
  """
  Requires permission `marketing:link:write`.
  
  Deletes a short link of your organization. Needs the marketing link write permission.
  """
  deleteShortUrl(
    """The ID of the short link."""
    id: String!
  ): Boolean!
  """
  Requires permission `products:tax:delete`.
  
  Deletes a tax group and its links to tax rates. It is refused while the catalog or the organization's defaults rely on the group. Needs the tax delete permission.
  """
  deleteTaxGroup(
    """The ID of the tax group."""
    id: ID!
  ): Boolean!
  """
  Requires permission `products:tax:delete`.
  
  Deletes a tax rate. It is refused while the rate is still in a tax group, or while the catalog or the organization's defaults rely on it. Needs the tax delete permission.
  """
  deleteTaxRate(
    """The ID of the tax rate."""
    id: ID!
  ): Boolean!
  """
  Requires permission `settings:tenant:delete`.
  
  Deletes a setting for good and returns it as it was. A category that has its own update operation is refused. Needs settings:tenant:delete.
  """
  deleteTenantSetting(
    """The ID of the setting."""
    id: String!
  ): TenantSetting!
  """
  Requires permission `products:product:delete`.
  
  Delete a unit of measure (a soft delete). Refused when the unit is the organization's default unit or is in use. Needs the products delete permission.
  """
  deleteUOM(
    """The ID of the unit of measure."""
    id: String!
  ): Boolean!
  """
  Requires permission `products:product:update`.
  
  Delete a conversion together with its reverse conversion (a soft delete). Needs the products update permission.
  """
  deleteUOMConversion(
    """The ID of the conversion to delete."""
    id: String!
  ): Boolean!
  """
  Requires permission `users:user:delete`.
  
  Deletes a user. You cannot delete your own account, and deleting another user needs every permission that user holds. A user in another organization is refused unless you hold the cross-organization user delete permission. Needs users:user:delete.
  """
  deleteUser(
    """The ID of the user."""
    id: String!
  ): User!
  """
  Requires permission `settings:webhooks:delete`.
  
  Deletes a webhook endpoint, which stops further deliveries to it. Requires permission to delete webhooks.
  """
  deleteWebhookEndpoint(
    """The ID of the webhook endpoint."""
    id: ID!
  ): Boolean!
  """
  Requires an authenticated session.
  
  Turns off two-factor sign-in for the signed-in user after checking their password.
  """
  disableTwoFactor(
    """The signed-in user's current password."""
    password: String!
  ): Boolean!
  """
  Requires permission `products:discount:create`.
  
  Creates a copy of a discount scheme with the same rules, validity window and priority. Fails if the scheme does not exist. Needs the discounts create permission.
  """
  duplicateDiscountScheme(
    """The ID of the discount scheme to copy."""
    id: String!
  ): DiscountScheme!
  """
  Requires at least one of the permissions `payments:invoice:create` or `purchase:purchase_invoice:create`.
  
  Creates a new invoice as a copy of an existing one, with the same lines and details, a new invoice number and the status DRAFT. The original is not changed. A user restricted to their own customers cannot copy an invoice outside that book.
  """
  duplicateInvoice(
    """The ID of the invoice to copy."""
    id: ID!
  ): Invoice!
  """
  Requires permission `sales:quote:create`.
  
  Copy an existing quote into a new DRAFT quote with a new quote number. Counts against the organization's monthly quote limit.
  """
  duplicateQuote(
    """The ID of the quote to copy."""
    id: ID!
  ): Quote!
  """
  Requires permission `sales:sales_order:create`.
  
  Copy an existing order into a new DRAFT order with a new order number.
  """
  duplicateSalesOrder(
    """The ID of the sales order to copy."""
    id: ID!
  ): SalesOrder!
  """
  Requires an authenticated session.
  
  Turns on two-factor sign-in by checking a code from the authenticator app against the setup started by setupTwoFactor. Fails if the setup has expired or the code is wrong.
  """
  enableTwoFactor(
    """The code from the authenticator app and an optional device name."""
    input: EnableTwoFactorInput!
  ): Boolean!
  """
  Requires at least one of the permissions `settings:currency:update` or `settings:tenant:update`.
  
  Ends an exchange rate of the organization from now on, without changing past documents. A rate that has not started yet is withdrawn instead, and a rate that has already ended is refused. Requires permission to update currency or tenant settings.
  """
  endTenantExchangeRate(
    """The ID of the rate and an optional end date."""
    input: EndTenantExchangeRateInput!
  ): TenantExchangeRate!
  """
  Requires permission `products:product:update`.
  
  DEPRECATED synchronous enrichment. Kept for backward compatibility; prefer the async startProductEnrichment / productEnrichmentJob pair. Needs the products update permission.
  """
  enrichProduct(
    """The ID of the product."""
    productId: ID!
  ): ProductEnrichmentSuggestion! @deprecated(reason: "Blocks the request for ~140s and exceeds the client HTTP timeout. Use startProductEnrichment + productEnrichmentJob.")
  """
  Requires permission `settings:backup:create`.
  
  Export all of the caller's organization data (GDPR portability). Needs the backup create permission.
  """
  exportMyOrganizationData: GdprExportResult!
  """
  Requires an authenticated session.
  
  Restarts the expiry of the current session for the full session duration, 7 days unless configured otherwise. Needs the session token header and an active session.
  """
  extendSession: ExtendSessionResponse!
  """
  Requires permission `products:brand:create`.
  
  Returns the brand with this name, matched without regard to case, or creates it when none exists. A new brand gets a generated code. An empty name is refused. Needs the brands create permission.
  """
  findOrCreateBrand(
    """The brand name. Leading and trailing spaces are ignored."""
    name: String!
  ): Brand!
  """
  Requires permission `categories:category:create`.
  
  Returns the category with this name, matched without regard to case, or creates it when none exists. A new category is active, sits at the top level and gets a generated code. An empty name is refused. Requires permission to create categories.
  """
  findOrCreateCategory(
    """The category name. Leading and trailing spaces are ignored."""
    name: String!
  ): Category!
  """
  Requires permission `products:product:create`.
  
  Find a unit of measure by name, ignoring case, or create it. A new unit gets the CUSTOM category, a code and symbol built from the name, and whole-number quantities. Used when importing product sheets. Needs the products create permission.
  """
  findOrCreateUOM(
    """The unit's name. It is matched ignoring case and surrounding spaces."""
    name: String!
  ): UnitOfMeasure!
  """
  Requires at least one of the permissions `settings:currency:update` or `settings:tenant:update`.
  
  Turns a currency off for the organization only, like deactivateCurrency. The base currency still cannot be deactivated. Requires permission to update currency or tenant settings.
  """
  forceDeactivateCurrency(
    """The ID of the currency."""
    id: String!
  ): Currency!
  """
  Requires permission `purchase:purchase_order:update`.
  
  Changes a purchase order in place, whatever its status, except that CANCELLED and CLOSED orders cannot be edited. Once a live goods receipt or purchase invoice references the order, its items, shipping, discount, freight, surcharge, currency and other financial fields are locked and the change is refused: received and billed quantities change only through a reversal document. Needs the purchase orders feature on your plan.
  """
  forceUpdatePurchaseOrder(
    """The details of the force update purchase order request."""
    input: ForceUpdatePurchaseOrderInput!
  ): PurchaseOrder!
  """
  Requires permission `catalog:copilot:chat`.
  
  Forget one fact Minori saved about the CALLER, by the key `copilotMemoryFacts` returned. Returns false when no live fact has that key.
  """
  forgetCopilotMemoryFact(
    """The key of the fact."""
    key: String!
  ): Boolean!
  """
  Public: no authentication required.
  
  Emails a password reset link to a staff account. It returns true whether or not an account matches, so the response does not reveal which email addresses have accounts. Rate-limited per IP address. No sign-in needed.
  """
  forgotPassword(
    """
    The email address and the organization subdomain. When the subdomain is omitted, the request host decides the organization.
    """
    forgotPasswordInput: ForgotPasswordInput!
  ): Boolean!
  """
  Requires permission `products:product:update`.
  
  Generates an EAN-13 barcode number from a SKU. The same SKU always gives the same number, and nothing is stored. Requires permission to update products.
  """
  generateBarcode(
    """The SKU to derive the barcode from."""
    sku: String!
  ): String!
  """
  Requires permission `commissions:commission:update`.
  
  Gathers a person's locked, unpaid commissions for one period into a pending payout. A period can only be paid once it has ended, and a period with nothing locked is refused. Running it again while the payout is still pending refreshes its total, and a payout already paid cannot be regenerated. Requires permission to update commissions.
  """
  generateCommissionPayout(
    """The person and the period, as YYYY-MM."""
    input: GeneratePayoutInput!
  ): CommissionPayout!
  """
  Requires permission `sales:credit_note:read`.
  
  Generate a PDF for a credit note and return base64 encoded data
  """
  generateCreditNotePdf(
    """The ID of the credit note."""
    creditNoteId: ID!
    """The name of the PDF template to use. Omit for the default."""
    template: String
  ): String!
  """
  Requires permission `purchase:debit_note:read`.
  
  Generate a PDF for a debit note and return base64 encoded data
  """
  generateDebitNotePdf(
    """The ID of the debit note."""
    debitNoteId: ID!
    """The name of the PDF template to use. Omit for the default."""
    template: String
  ): String!
  """
  Requires at least one of the permissions `payments:invoice:read` or `purchase:purchase_invoice:read`.
  
  Generate a PDF for an invoice and return base64 encoded data
  """
  generateInvoicePdf(
    """The ID of the invoice."""
    invoiceId: ID!
    """
    The PDF template: professional, modern or classic. Omit to use the organization's default.
    """
    template: String
  ): String!
  """
  Requires at least one of the permissions `settings:appearance:update` or `settings:tenant:update`.
  
  Returns a short-lived URL to upload a logo or favicon image straight to storage, plus the public URL it will have. Only image files are accepted. It saves nothing: set the public URL with updateAppearanceSettings afterwards. Needs settings:appearance:update, or settings:tenant:update.
  """
  generateLogoUploadUrl(
    """The image's file name."""
    fileName: String!
    """The image's MIME type: JPEG, PNG, WebP, GIF or SVG."""
    fileType: String!
    """Whether the image is the logo or the favicon."""
    logoType: String!
  ): LogoUploadResponse!
  """
  Requires permission `visits:journey-plan:generate-own`.
  
  Generates a route plan for the signed-in rep's own cycle, in the same way as generateRoutePlan. Requires permission to manage journey plans.
  """
  generateMyRoutePlan(
    """How many days the cycle lasts."""
    cycleLengthDays: Int!
    """The first day of the cycle."""
    cycleStartDate: DateTime!
  ): GenerateRoutePlanResult!
  """
  Requires at least one of the permissions `payments:payment:read` or `purchase:payment:read`.
  
  Generate a PDF for a payment/collection and return base64 encoded data
  """
  generatePaymentPdf(
    """The ID of the payment."""
    paymentId: ID!
    """The name of the PDF template to use. Omit for the default."""
    template: String
  ): String!
  """
  Requires permission `products:import:read`.
  
  S2.1 — materializes ALL failed rows (original columns + an errors column) as a re-uploadable CSV in object storage and returns a short-lived presigned download URL. Cached on errorFileRef.
  """
  generateProductImportErrorFile(
    """The ID of the import."""
    importId: String!
  ): ProductImportErrorFile!
  """
  Requires permission `purchase:purchase_order:read`.
  
  Generate a PDF for a purchase order and return base64 encoded data
  """
  generatePurchaseOrderPdf(
    """The ID of the purchase order."""
    purchaseOrderId: ID!
    """The name of the PDF template to use. Omit for the default."""
    template: String
  ): String!
  """
  Requires permission `sales:quote:read`.
  
  Generate a PDF for a quote and return base64 encoded data
  """
  generateQuotePdf(
    """The ID of the quote."""
    quoteId: ID!
    """
    The PDF template: professional, modern or classic. Omit to use the organization's default.
    """
    template: String
  ): String!
  """
  Requires permission `visits:journey-plan:manage`.
  
  Generates a route plan for one sales rep over a cycle of days from a start date, grouping their customers by location and visit cadence. The caller needs authority over that rep. Requires permission to manage journey plans.
  """
  generateRoutePlan(
    """
    The rep, the cycle length in days, the cycle start date and whether to include Sundays.
    """
    input: GenerateRoutePlanInput!
  ): GenerateRoutePlanResult!
  """
  Requires at least one of the permissions `products:product:create` or `products:product:update`.
  
  Generates the next SKU from the active SKU pattern that matches the brand and category, or a plain sequential SKU with an optional prefix when none matches. The result says whether the SKU is free, and failures come back in the result instead of as an error. Needs the products create or update permission.
  """
  generateSKU(
    """The optional brand, category, prefix and custom pattern variables."""
    generateSKUInput: GenerateSKUInput!
  ): GeneratedSKU!
  """
  Requires permission `sales:sales_order:read`.
  
  Generate a PDF for a sales order and return base64 encoded data
  """
  generateSalesOrderPdf(
    """The ID of the sales order."""
    salesOrderId: ID!
    """
    The PDF template: professional, modern or classic. Omit to use the organization's default.
    """
    template: String
  ): String!
  """
  Public: no authentication required.
  
  Signs in with a Google ID token. When no user matches the Google account it returns signupRequired and the Google profile instead of signing in. Customer accounts are refused, and so are accounts without admin-console access when called from the console. A required second factor cannot be skipped. On success it returns tokens and a session token and sets sign-in cookies for web clients. No sign-in needed.
  """
  googleAuth(
    """The Google ID token returned by Google sign-in."""
    token: String!
  ): GoogleAuthResponse!
  """
  Requires permission `products:product:update`.
  
  Download an approved public image URL and store a hosted copy under the org prefix. Returns the hosted URL to add to the product imageUrls. Needs the products update permission.
  """
  ingestProductImage(
    """The address of the image to fetch."""
    url: String!
  ): IngestedImage!
  """
  Requires permission `settings:tenant:create`.
  
  Creates the standard set of default settings for the organization. Settings that already exist are left as they are. Returns true on success. Needs settings:tenant:create.
  """
  initializeDefaultSettings: Boolean!
  """
  Requires permission `customers:customer_user:create`.
  
  Invites a person to sign in for a customer company and sends them a single-use link that expires. They sign in with one-time codes only. Needs customers:customer_user:create.
  """
  inviteCustomerUser(
    """
    The company, the person's email and name, their role, order limit, whether they approve orders, and the addresses assigned to them.
    """
    input: InviteCustomerUserInput!
  ): InviteCustomerUserResult!
  """
  Requires permission `storefront:storefront:read`.
  
  A closing storefront editor window says goodbye, so the others stop listing it at once instead of after 90 seconds. Best effort: true when it was listed.
  """
  leaveStorefrontEditor(
    """
    The closing window's own id, as its heartbeats sent it. Only the signed-in person's own window is removed.
    """
    sessionId: String!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Attaches the visits a guest made before signing in to the signed-in customer's company. Returns how many were linked.
  """
  linkGuestActivity(
    """The identifier the app gave the guest before sign-in."""
    anonymousId: String!
  ): LinkGuestActivityResult!
  """
  Requires permission `settings:tenant:update`.
  
  Manually lock base currency (admin only)
  """
  lockBaseCurrency: Boolean!
  """
  Public: no authentication required.
  
  Signs in with an email and password. It returns tokens and a session token and sets sign-in cookies for web clients; when a second factor is required it returns a temporary token to finish with verifyTwoFactor. Rate-limited per IP address, and repeated failed attempts lock the account for a while. A failed sign-in returns one generic error that does not say whether the email has an account. No sign-in needed.
  """
  login(
    """
    The email, the password, the organization subdomain and optional second-factor code and device settings.
    """
    loginInput: LoginInput!
  ): AuthResponse!
  """
  Public: no authentication required.
  
  Signs in with the code from requestLoginOtp. A code works once and expires after 5 minutes. Returns tokens and a session token and sets sign-in cookies for web clients. Rate-limited per IP address. No sign-in needed.
  """
  loginWithOtp(
    """
    The email address, the code, the organization subdomain and optional device-trust settings.
    """
    loginWithOtpInput: LoginWithOtpInput!
  ): AuthResponse!
  """
  Requires an authenticated session.
  
  Signs the user out: clears the sign-in cookies and ends the current session.
  """
  logout: Boolean!
  """
  Requires permission `notifications:user-notification:mark-read`.
  
  Marks all of the signed-in user's unread notifications as read and returns how many were changed. Requires permission to mark notifications read.
  """
  markAllNotificationsRead: Int!
  """
  Requires permission `commissions:commission:update`.
  
  Settles a payout: marks it and all its commissions paid. A payout that is already settled cannot be marked again. Requires permission to update commissions.
  """
  markCommissionPayoutPaid(
    """The payout and an optional payment reference."""
    input: MarkPayoutPaidInput!
  ): CommissionPayout!
  """
  Requires permission `sales:quote:read`.
  
  Marks every unread customer reply on one quote as read. It only affects quotes the caller may open, and it returns whether anything changed. Requires permission to read quotes.
  """
  markInboundEmailsAsRead(
    """The ID of the quote."""
    quoteId: ID!
  ): Boolean!
  """
  Requires permission `notifications:user-notification:mark-read`.
  
  Marks one of the signed-in user's own notifications as read. Anyone else's notification reads as missing. Requires permission to mark notifications read.
  """
  markNotificationRead(
    """The ID of the notification."""
    id: ID!
  ): UserNotification!
  """
  Requires permission `inventory:stock_movement:create`.
  
  Marks a return as RECEIVED and stamps the actual return date. This is the step that makes the return eligible for inspection (`processReturnInspection`). Needs the stock movement create permission and permission to read the return.
  """
  markReturnReceived(
    """
    The items and quantities actually received. Omit to receive everything.
    """
    receivedItems: [PartialReturnItemInput!]
    """The ID of the return."""
    returnId: String!
  ): ReturnResponse!
  """
  Requires permission `sales:sales_order:deliver`.
  
  Mark a fully shipped order as delivered and stamp its delivery date, which opens the customer's return window. deliveredAt back-dates a delivery recorded later and never moves an existing date.
  """
  markSalesOrderDelivered(
    """
    When the delivery happened. Use it to back-date a delivery recorded later; it never moves an existing delivery date.
    """
    deliveredAt: DateTime
    """
    The version of the record you last read. The change is refused if someone else changed it since.
    """
    expectedVersion: Int
    """The ID of the sales order."""
    id: ID!
  ): SalesOrder!
  """
  Requires permission `sales:sales_order:ship`.
  
  Record that the seller paid the courier for a shipment (date YYYY-MM-DD, method, reference). Refused for a cancelled shipment or a failed booking. Re-marking overwrites the record (audited). Recording only — no money moves.
  """
  markShipmentCourierPaid(
    """The details of the mark shipment courier paid request."""
    input: MarkShipmentCourierPaidInput!
    """The ID of the shipment."""
    shipmentId: ID!
  ): ShipmentGql!
  """
  Requires permission `sales:sales_order:ship`.
  
  Record ONE courier payment (date YYYY-MM-DD, method, reference) on many shipments at once (1–500). All or nothing: refused when any shipment is not found, cancelled / booking failed, or already marked paid. Returns the courier charges settled per currency. Recording only — no money moves. Each shipment is audited.
  """
  markShipmentsCourierPaid(
    """The details of the mark shipments courier paid request."""
    input: MarkShipmentsCourierPaidInput!
  ): MarkShipmentsCourierPaidResultGql!
  """
  Requires at least one of the permissions `settings:sales:create` or `settings:tenant:update`.
  
  Turn the platform default set into real, editable rows for this organization. Idempotent.
  """
  materializePaymentTerms: [PaymentTerm!]!
  """
  Public: no authentication required.
  
  Mint a single-use INSTALL HANDOFF code for an invite. The portal /invite page passes it through the Play Store referrer (Android) or the clipboard (iOS) so the newly installed buyer app can claim the invite (mobileClaimInvite) with nothing typed. Never the invite token itself.
  """
  mintInviteInstallHandoff(
    """The details of the invite install handoff to mint."""
    input: MintInviteInstallHandoffInput!
  ): String!
  """
  Public: no authentication required.
  
  Accept a team invite from the buyer app: verifies the OTP against the token's own email, activates the user and returns a MOBILE session.
  """
  mobileAcceptInvite(
    """The details of the mobile accept invite request."""
    input: MobileAcceptInviteInput!
  ): MobileAuthResponse!
  """
  Requires a customer (portal or buyer app) session.
  
  Add every line of a partner-shared buying list onto the buyer's shared cart (the same cart the customer portal shows). Returns a summary — a buyer who taps once must be told what was added and what was skipped.
  """
  mobileAddListToCart(
    """The ID of the buying list."""
    listId: ID!
  ): MobileAddListToCartResult!
  """
  Requires a customer (portal or buyer app) session.
  
  Add a product variant to the buyer's shared cart.
  """
  mobileAddToCart(
    """The details of the mobile add to cart request."""
    input: MobileAddToCartInput!
  ): MobileCart!
  """
  Requires a customer (portal or buyer app) session.
  
  Apply several cart writes (adds, absolute-quantity updates, removes) in one call and one save — the bulk order confirm. All-or-nothing: if any line is refused, the cart is left unchanged.
  """
  mobileApplyCartChanges(
    """The details of the mobile apply cart changes request."""
    input: MobileApplyCartChangesInput!
  ): MobileCart!
  """
  Public: no authentication required.
  
  Claim an invite with an exact credential — the invite token (link opened in the app) or an install handoff code (Play referrer / iOS clipboard) — accepting it and returning a MOBILE session. Only accepts a PENDING invite; never a login for an existing account.
  """
  mobileClaimInvite(
    """The details of the mobile claim invite request."""
    input: MobileClaimInviteInput!
  ): MobileAuthResponse!
  """
  Requires a customer (portal or buyer app) session.
  
  Remove every item from the buyer's shared cart in one call.
  """
  mobileClearCart: MobileCart!
  """
  Public: no authentication required.
  
  Self-register a new buyer (Name/Company/Email/Business Type): creates a PENDING_APPROVAL customer and sends the login OTP. Rejects an email that already has a customer.
  """
  mobileRegisterBuyer(
    """The details of the mobile register buyer request."""
    input: MobileRegisterBuyerInput!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Remove a cart item.
  """
  mobileRemoveCartItem(
    """The details of the mobile remove cart item request."""
    input: MobileRemoveCartItemInput!
  ): MobileCart!
  """
  Requires a customer (portal or buyer app) session.
  
  Set quantity for a cart item; quantity 0 removes the line.
  """
  mobileUpdateCartItem(
    """The details of the mobile update cart item request."""
    input: MobileUpdateCartItemInput!
  ): MobileCart!
  """
  Public: no authentication required.
  
  Verify a buyer registration OTP WITHOUT creating an account or issuing tokens — the step before the create-account form. Returns true/false; `mobileRegisterBuyer` re-checks the same code as proof this step was passed. Named `mobile*` because the auth module already owns a DIFFERENT `verifyRegistrationOtp` (staff, token-returning) and GraphQL field names are global.
  """
  mobileVerifyRegistrationOtp(
    """The details of the verify email otp request."""
    input: VerifyEmailOtpInput!
  ): Boolean!
  """
  Requires permission `sales:sales_order:approve`.
  
  Approve one of a customer account's parked over-limit checkouts from the SELLER's console. Replays the cart snapshot through the canonical checkout path with a fresh reprice and returns the created order — the same service call the buyer app makes. Errors: APPROVAL_NOT_PENDING, OVER_CREDIT_LIMIT.
  """
  partnerApproveOrderRequest(
    """The ID of the partner."""
    partnerId: ID!
    """The ID of the approval request."""
    requestId: ID!
  ): CustomerApprovalDecisionResult!
  """
  Requires permission `sales:sales_order:approve`.
  
  Decline one of a customer account's parked over-limit checkouts from the SELLER's console, with an optional reason the buyer sees. Terminal. Errors: APPROVAL_NOT_PENDING.
  """
  partnerDeclineOrderRequest(
    """The ID of the partner."""
    partnerId: ID!
    """Why the request is declined."""
    reason: String
    """The ID of the approval request."""
    requestId: ID!
  ): CustomerApprovalDecisionResult!
  """
  Requires permission `catalog:copilot:chat`.
  
  Pauses one of the caller's own scheduled copilot tasks, so it stops running on its schedule. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  pauseCopilotScheduledJob(
    """The ID of the scheduled task."""
    id: ID!
  ): CopilotScheduledJobType!
  """
  Requires permission `inventory:stock_movement:create`.
  
  Records the quality check of one returned item: its score, whether it passed, and notes. The item must belong to the organization. Needs the stock movement create permission and permission to read the return.
  """
  performQualityCheck(
    """The score, whether the item passed, and optional notes."""
    input: QualityCheckInput!
    """The ID of the return item."""
    returnItemId: String!
  ): ProductReturnItem!
  """
  Requires permission `catalog:copilot:chat`.
  
  Pin (or unpin) one of the CALLER'S OWN chats to the top of their list.
  """
  pinCopilotSession(
    """The ID of the Copilot session."""
    id: ID!
    """True to pin the session, false to unpin it."""
    pinned: Boolean!
  ): CopilotSessionSummary!
  """
  Requires a customer (portal or buyer app) session.
  
  Place a Cash-on-Delivery order. Network retries must reuse the same idempotencyKey — server returns the previously created order.
  """
  placeOrder(
    """The details of the place order request."""
    input: PlaceOrderInput!
  ): MobileOrder!
  """
  Requires a customer (portal or buyer app) session.
  
  step 5: real checkout — customerCart → placeOrder through ordersService.createSalesOrder (idempotency key, credit-limit path, tenant isolation all live there). Every line is re-resolved server-side before the order is created; the mock setTimeout flow is retired.
  """
  placeOrderFromCart(
    """The details of the place order from cart request."""
    input: PlaceOrderFromCartInput!
  ): PlaceOrderFromCartResult!
  """
  Requires at least one of the permissions `payments:payment:update` or `purchase:payment:update`.
  
  Marks a payment as PROCESSED. When the payment has a bank account, that account's balance moves in the same step: down for a payment to a supplier and up for a collection. A payment that is already processed is refused.
  """
  processPayment(
    """The ID of the payment to process."""
    paymentId: ID!
  ): Payment!
  """
  Requires permission `sales:credit_note:create`.
  
  Processes a PENDING return. With `action` PROCESS (or APPROVE, which means the same here) the return becomes PROCESSED: for each restockable line with an accepted quantity, stock moves through the inventory ledger (stock comes back for a sales return and leaves for a purchase return), and a credit note (sales return) or debit note (purchase return) is created when you send its details. For each line, accepted plus rejected cannot exceed the quantity returned. A note amount above the value of the accepted lines is refused unless you hold the override-note-amount permission. With `action` REJECT the return is closed without touching stock or money. Only a PENDING return can be processed, and only once.
  """
  processReturn(
    """The details of the process return request."""
    input: ProcessReturnInput!
  ): ProcessReturnResponse!
  """
  Requires permission `inventory:stock_movement:create` and at least one of `purchase:debit_note:create` or `sales:credit_note:create`.
  
  Records the inspection of a RECEIVED return and completes it: for each line, the accepted, rejected and restock quantities. Accepted plus rejected cannot exceed the quantity returned, and the restock quantity cannot exceed the accepted quantity. A return that is not yet received is refused, and inspection can run only once: a return changed or already processed asks you to refresh and try again. It moves stock and issues the credit note (customer return) or debit note (supplier return), so it needs the stock movement create permission and that direction's note create permission.
  """
  processReturnInspection(
    """The details of the inspection request."""
    input: InspectionInput!
    """The ID of the return."""
    returnId: String!
  ): ReturnActionResult!
  """
  Requires at least one of the permissions `purchase:debit_note:update` or `sales:credit_note:update`.
  
  Records the refund amount and method on a return and moves it to PROCESSING. It records the decision; it does not move money by itself. Needs the update permission of the return's direction.
  """
  processReturnRefund(
    """The details of the process refund request."""
    input: ProcessRefundInput!
    """The ID of the return."""
    returnId: String!
  ): ReturnResponse!
  """
  Requires permission `storefront:storefront:publish`.
  
  Publish the saved storefront draft: it is checked, frozen as the next version, and buyers see it. Refused, with every reason, when it would not draw; refused with VERSION_CONFLICT when `expectedUpdatedAt` is given and the draft was saved since.
  """
  publishStorefrontTheme(
    """
    The stored draft's updatedAt as the editor saved it: publishing is refused when the draft was saved since.
    """
    expectedUpdatedAt: DateTime
  ): StorefrontThemeVersionSummary!
  """
  Requires permission `products:product:update`.
  
  Quick update a single product field - optimized for spreadsheet editing
  """
  quickUpdateProductField(
    """The name of the product field to change."""
    field: String!
    """The ID of the product."""
    productId: String!
    """The new value. Send null to clear the field."""
    value: String
  ): Boolean!
  """
  Requires permission `products:product:update`.
  
  Quick update a single variant field - optimized for spreadsheet editing
  """
  quickUpdateVariantField(
    """The name of the variant field to change."""
    field: String!
    """The new value. Send null to clear it."""
    value: String
    """The ID of the product variant."""
    variantId: ID!
  ): Boolean!
  """
  Requires permission `catalog:copilot:chat`.
  
  Rate an ASSISTANT turn of one of the CALLER'S OWN copilot threads (UP/DOWN + optional note). The message must exist in the thread; anything else is 400.
  """
  rateCopilotMessage(
    """The ID of the Copilot session."""
    id: ID!
    """The ID of the message being rated."""
    messageId: ID!
    """An optional comment."""
    note: String
    """The rating: "up" or "down"."""
    rating: String!
  ): Boolean!
  """
  Requires permission `customers:customer_user:update`.
  
  Restores a deactivated customer user to the state they had before, for example an invitation still waiting to be accepted. Needs customers:customer_user:update.
  """
  reactivateCustomerUser(
    """The ID of the customer user."""
    userId: ID!
  ): Boolean!
  """
  Requires permission `sales:sales_order:allocate`.
  
  Release and re-run warehouse allocation for a confirmed order, honoring any manual splits. A shortage never rejects the call; it appears as BACKORDER rows.
  """
  reallocateSalesOrder(
    """The ID of the sales order."""
    id: ID!
  ): [SalesOrderItemAllocation!]!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:create`, `payments:collection:create`, `payments:collection:update`, `payments:payment:allocate`, `payments:payment:create`, `payments:payment:update`, `purchase:grn:create`, `purchase:grn:update`, `purchase:payment:allocate`, `purchase:payment:create`, `purchase:payment:update`, `purchase:purchase_invoice:create`, `purchase:purchase_invoice:update`, `purchase:purchase_order:approve`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:credit_note:create`, `sales:sales_order:confirm`, `sales:sales_order:deliver`, `sales:sales_order:ship`, `sales:sales_order:update`, `sales:shipment:create` or `sales:shipment:update`.
  
  Recalls a pending approval request you raised, for example to edit the document. Only the requester can recall, and only while it is pending.
  """
  recallControlRequest(
    """The approval request's ID."""
    id: ID!
  ): ControlApprovalRequest!
  """
  Requires permission `purchase:purchase_order:update`.
  
  Disabled: direct receiving always refuses. Receive goods by creating a goods receipt note with `createGRN`.
  """
  receivePurchaseOrder(
    """The details of the receive purchase order request."""
    input: ReceivePurchaseOrderInput!
  ): PurchaseOrder! @deprecated(reason: "Direct receiving is disabled; create a GRN (createGRN) to receive against a purchase order.")
  """
  Requires at least one of the permissions `settings:customer_tiers:update` or `settings:tenant:update`.
  
  Re-evaluates the tier of every unlocked customer and returns how many were upgraded. It returns 0 when the module or automatic tiering is off. Requires permission to update customer tier or tenant settings.
  """
  recomputeCustomerTiers: Int!
  """
  Requires a customer (portal or buyer app) session.
  
  Records a batch of buyer-app interaction events, such as views and searches, for the signed-in buyer. Any signed-in buyer can call it, and calls are rate limited.
  """
  recordBuyerActivity(
    """The events to record."""
    input: RecordBuyerActivityInput!
  ): RecordBuyerActivityResult!
  """
  Requires permission `communications:consent:update`.
  
  Records a contact's consent status for a channel and purpose, with where it came from. The contact's customer must be in the caller's own book. Requires permission to update consent.
  """
  recordContactConsent(
    """The contact, channel, purpose, consent status and source."""
    input: RecordContactConsentInput!
  ): ContactConsentGql!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:export`, `inventory:stock_transfer:export`, `payments:collection:export`, `payments:invoice:export`, `payments:payment:export`, `purchase:grn:export`, `purchase:payment:export`, `purchase:purchase_invoice:export`, `purchase:purchase_order:export` or `sales:sales_order:export`.
  
  Writes the audit entry for a completed export. Call it when the file is actually downloaded, not when the dialog opens. Needs the export permission for that document type. Returns true.
  """
  recordExport(
    """
    The export key that identifies the document type, and the label of the record being exported.
    """
    input: AuthorizeExportInput!
  ): Boolean!
  """
  Requires permission `sales:shipment:update`.
  
  Records a shipment status by hand, for a custom courier only. A courier that reports its own status is refused: use `refreshShipmentTracking` instead. Only statuses staff may set by hand are accepted (awaiting pickup, picked up, in transit, out for delivery, delivered, failed attempt, exception, returned to sender and lost), and the move must be allowed from the shipment's current status. Marking an order's outbound shipment DELIVERED also needs the sales order deliver permission, because it can mark the order delivered. Needs the delivery partners feature on your plan and the shipment update permission.
  """
  recordShipmentStatus(
    """The ID of the shipment."""
    id: ID!
    """The details of the record shipment status request."""
    input: RecordShipmentStatusInput!
  ): ShipmentGql!
  """
  Public: no authentication required.
  
  Exchange a valid refresh token for a fresh access + refresh token pair.
  """
  refreshAccessToken(
    """The details of the mobile refresh token request."""
    input: MobileRefreshTokenInput!
  ): MobileAuthResponse!
  """
  Requires permission `sales:shipment:update`.
  
  Asks the carrier for the latest status now and updates the shipment from the answer. Needs the delivery partners feature on your plan and the shipment update permission.
  """
  refreshShipmentTracking(
    """The ID of the shipment."""
    id: ID!
  ): ShipmentGql!
  """
  Public: no authentication required.
  
  Exchanges a refresh token for a new access token and refresh token, and sets new sign-in cookies for web clients. Rate-limited per IP address. No sign-in needed: the refresh token is the credential.
  """
  refreshToken(
    """The refresh token."""
    refreshTokenInput: RefreshTokenInput!
  ): AuthResponse!
  """
  Public: no authentication required.
  
  Portal self-registration — CREATES the account, gated on the OTP code the caller already verified (re-checked here, never consumed: the sign-in that follows spends it). Honoured only when allowSelfRegistration is on; the response previews whether the new account needs seller approval, and is uniform whether or not the email exists.
  """
  registerCustomer(
    """The details of the customer to register."""
    input: RegisterCustomerInput!
  ): PortalRegisterAccountResult!
  """
  Requires permission `settings:integration:update`.
  
  Registers this organization's webhook URL through the delivery provider's own API. A provider without such an API is refused, with a note that its webhook is set up in its own dashboard. Needs the delivery partners plan feature and permission to update integrations.
  """
  registerDeliveryPartnerWebhook(
    """The ID of the delivery partner configuration."""
    id: ID!
  ): DeliveryPartnerVerification!
  """
  Requires permission `notifications:push-token:manage`.
  
  Registers a push-notification token for the signed-in staff user's device. Requires permission to manage push tokens.
  """
  registerMyPushToken(
    """
    The push token, the device ID, the platform and optionally the app version.
    """
    input: RegisterPushTokenInput!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Register an Expo push token for the buyer's device.
  """
  registerPushToken(
    """The details of the push token to register."""
    input: RegisterPushTokenInput!
  ): Boolean!
  """
  Public: no authentication required.
  
  Creates a new organization and its first admin user from a Google account. Rate-limited per IP address. No sign-in needed.
  """
  registerWithGoogle(
    """The Google token and the details of the organization to create."""
    input: GoogleRegisterInput!
  ): GoogleRegisterResponse!
  """
  Public: no authentication required.
  
  Step 3 of registering an organization by email: creates the organization and its first admin user. It needs the verification token from verifyRegistrationOtp and returns an onboarding ID for following progress. Rate-limited per IP address. No sign-in needed.
  """
  registerWithOtp(
    """
    The email address, the verification token and the details of the organization to create.
    """
    input: OtpRegisterInput!
  ): OtpRegisterResponse!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve` or `purchase:purchase_order:approve`.
  
  Rejects a pending approval request with a reason (1 to 500 characters). A rejected request is final; the requester runs the action again to raise a new one. Same signer rules as approveControlRequest.
  """
  rejectControlRequest(
    """The approval request's ID."""
    id: ID!
    """Why, 1 to 500 characters."""
    reason: String!
  ): ControlApprovalRequest!
  """
  Requires permission `catalog:copilot:chat`.
  
  Rejects a change the copilot proposed in the caller's own chat, optionally with a reason and a note that help the copilot learn. Limited to 30 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  rejectCopilotProposal(
    """An optional note. A note over 280 characters is shortened."""
    note: String
    """The ID of the proposal."""
    proposalId: ID!
    """
    An optional reason code: wrong customer, wrong items, wrong quantity or unit, wrong price, wrong details, not needed, or other.
    """
    reason: String
    """The ID of the copilot chat the proposal is in."""
    sessionId: ID!
  ): ProposalCardType!
  """
  Requires at least one of the permissions `purchase:debit_note:approve` or `sales:credit_note:approve`.
  
  Rejects a return request with a reason. A completed or cancelled return cannot be rejected, a return that already has a live credit note is refused, and so is a purchase return that has already posted stock or a debit note. Needs the approve permission of the return's direction.
  """
  rejectRMA(
    """Why the return is rejected."""
    reason: String!
    """The ID of the return."""
    returnId: String!
  ): ReturnResponse!
  """
  Requires a customer (portal or buyer app) session.
  
  Soft-delete an address owned by the buyer.
  """
  removeAddress(
    """The ID of the address."""
    addressId: ID!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  remove one manager from a branch (CUSTOMER_ADMIN only).
  """
  removeBranchManager(
    """The ID of the address."""
    addressId: ID!
    """The ID of the user."""
    userId: ID!
  ): CustomerBranch!
  """
  Requires a customer (portal or buyer app) session.
  
  Removes one line from the cart. Pass the cart revision you last saw, and an operation ID so a retry applies once.
  """
  removeCartItem(
    """
    The cart line to remove, the expected cart revision and the operation ID.
    """
    input: RemoveCartItemInput!
  ): CartType!
  """
  Requires an authenticated session.
  
  Removes one person from a channel. The channel's creator cannot be removed. Only an admin or manager, or an admin of that channel, can do this. Needs a signed-in user.
  """
  removeChannelMember(
    """The ID of the chat channel."""
    channelId: String!
    """The ID of the person to remove."""
    memberId: String!
  ): ChatChannel!
  """
  Requires a customer (portal or buyer app) session.
  
  Remove a person from the buyer's account.
  """
  removeContact(
    """The ID of the contact."""
    id: ID!
  ): Boolean!
  """
  Requires permission `sales:credit_note:delete`.
  
  Deletes a credit note. Only a DRAFT or PENDING note can be deleted. If the note had earned a rep commission, that commission is given back.
  """
  removeCreditNote(
    """The ID of the credit note."""
    id: ID!
  ): CreditNote!
  """
  Requires permission `customers:customer:delete`.
  
  Deletes a customer. Refused while the customer has draft, confirmed, partially invoiced or invoiced orders. If the record also has the supplier role, only the customer role is removed. Needs the customers delete permission.
  """
  removeCustomer(
    """The ID of the customer."""
    id: ID!
  ): Customer!
  """
  Requires permission `purchase:debit_note:delete`.
  
  Deletes a debit note. A note that has been applied cannot be deleted. Needs the debit notes feature on your plan.
  """
  removeDebitNote(
    """The ID of the debit note."""
    id: ID!
  ): DebitNoteResponse!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Removes the organization's registered sender domain. Requires permission to update email settings.
  """
  removeEmailSenderDomain: Boolean!
  """
  Requires permission `purchase:grn:delete`.
  
  Deletes a goods receipt. A GRN that has posted stock cannot be deleted, because a posted receipt cannot be reversed: correct it with an inventory adjustment or a purchase return. A GRN with lines already billed on a purchase invoice cannot be deleted either. Needs the goods receipt (GRN) feature on your plan.
  """
  removeGRN(
    """The ID of the goods receipt note."""
    id: ID!
  ): GRN!
  """
  Requires at least one of the permissions `settings:organization:update` or `settings:tenant:update`.
  
  Removes a custom hostname and releases it. The platform hostname cannot be removed. Returns true on success. Needs settings:organization:update, or settings:tenant:update.
  """
  removeOrganizationDomain(
    """The ID of the domain."""
    id: ID!
  ): Boolean!
  """
  Requires at least one of the permissions `customers:customer:delete` or `suppliers:supplier:delete`.
  
  Deletes a partner. A customer needs the customers delete permission, a supplier the suppliers delete permission, and a partner with both roles needs both. Refused while the partner has open orders.
  """
  removePartner(
    """The ID of the partner."""
    id: ID!
  ): Partner!
  """
  Requires permission `settings:permission:update`.
  
  Removes a permission from a role. Returns true on success. Needs settings:permission:update.
  """
  removePermissionFromRole(
    """The role and the permission to remove."""
    input: RemovePermissionInput!
  ): Boolean!
  """
  Requires permission `products:product:delete`.
  
  Deletes a product together with its variants and its discount scheme entries. A product with stock on hand is refused; adjust the stock to zero first. Requires permission to delete products.
  """
  removeProduct(
    """The ID of the product."""
    id: String!
  ): Product!
  """
  Requires permission `products:product:update`.
  
  Remove a unit (pack) from a product or variant (a soft delete). The base unit cannot be removed; change the base unit first. Needs the products update permission.
  """
  removeProductUOM(
    """The ID of the product unit (pack) to remove."""
    id: String!
  ): Boolean!
  """
  Requires permission `products:brand:update`.
  
  Detach products from a brand (clears the product's brand). Only products currently on this brand are affected. Needs the brands update permission.
  """
  removeProductsFromBrand(
    """The ID of the brand."""
    brandId: ID!
    """The IDs of the products."""
    productIds: [ID!]!
  ): BrandProductAssignmentResult!
  """
  Requires permission `products:product:update`.
  
  Detach products from a category. Only products currently in this category are affected; the product's other categories are untouched.
  """
  removeProductsFromCategory(
    """The ID of the category."""
    categoryId: ID!
    """The IDs of the products."""
    productIds: [ID!]!
  ): CategoryProductAssignmentResult!
  """
  Requires permission `purchase:purchase_order:delete`.
  
  Deletes a purchase order. Only DRAFT or CANCELLED orders can be deleted. Needs the purchase order delete permission and the purchase orders feature on your plan.
  """
  removePurchaseOrder(
    """The ID of the purchase order."""
    id: ID!
  ): PurchaseOrder!
  """
  Requires permission `sales:quote:delete`.
  
  Delete a quote. Only DRAFT or CANCELLED quotes can be deleted; any other status is refused. The quote is soft-deleted and returned.
  """
  removeQuote(
    """The ID of the quote."""
    id: ID!
  ): Quote!
  """
  Requires permission `settings:role:delete`.
  
  Deletes a role by soft-deleting it. System roles cannot be deleted. Returns true on success. Needs settings:role:delete.
  """
  removeRole(
    """The ID of the role."""
    id: ID!
  ): Boolean!
  """
  Requires permission `sales:sales_order:delete`.
  
  Delete an order. Only DRAFT or CANCELLED orders can be deleted, and not when invoices are linked to them. The order is soft-deleted and returned.
  """
  removeSalesOrder(
    """The ID of the sales order."""
    id: ID!
  ): SalesOrder!
  """
  Requires at least one of the permissions `settings:regional:delete` or `settings:tenant:update`.
  
  Removes one of the organization's timezones. Requires permission to delete regional settings or update tenant settings.
  """
  removeTimezone(
    """The ID of the timezone."""
    id: String!
  ): Timezone!
  """
  Requires permission `products:product:update`.
  
  Remove a unit's icon image and delete the stored file. Needs the products update permission.
  """
  removeUOMImage(
    """The ID of the unit of measure."""
    uomId: String!
  ): Boolean!
  """
  Requires permission `settings:role:update`.
  
  Removes a user from a role. Returns true on success. Needs settings:role:update.
  """
  removeUserFromRole(
    """The user and the role to remove them from."""
    input: RemoveUserFromRoleInput!
  ): Boolean!
  """
  Requires permission `settings:permission:update`.
  
  Removes a direct permission grant from a user. Returns true on success. Needs settings:permission:update.
  """
  removeUserPermission(
    """The user and the permission to remove."""
    input: RemoveUserPermissionInput!
  ): Boolean!
  """
  Requires permission `users:user:update`.
  
  Removes a reporting relationship by soft-deleting it. Needs users:user:update.
  """
  removeUserRelationship(
    """The ID of the user relationship."""
    id: String!
  ): UserRelationship!
  """
  Requires permission `suppliers:supplier:update`.
  
  Deletes a supplier-to-variant mapping. Needs the suppliers update permission.
  """
  removeVendorProduct(
    """The ID of the vendor product mapping."""
    id: ID!
  ): VendorProduct!
  """
  Requires permission `inventory:warehouse:delete`.
  
  Deletes a warehouse. It is refused while the warehouse still holds stock; transfer the stock to another warehouse or adjust it to zero first. Needs the warehouse delete permission.
  """
  removeWarehouse(
    """The ID of the warehouse."""
    id: ID!
  ): Warehouse!
  """
  Requires permission `catalog:copilot:chat`.
  
  Rename one of the CALLER'S OWN copilot threads (trimmed, max 120 chars).
  """
  renameCopilotSession(
    """The ID of the Copilot session."""
    id: ID!
    """The new title."""
    title: String!
  ): CopilotSessionSummary!
  """
  Requires permission `products:product:update`.
  
  Renames a product attribute on every product carrying it and in the product finders that name it. Requires permission to update products.
  """
  renameProductAttribute(
    """The attribute and its new name."""
    input: RenameProductAttributeInput!
  ): ProductAttributeChangeResult!
  """
  Requires permission `products:product:update`.
  
  Renames one value of a product attribute on every product carrying it and in the product finders that name it. Requires permission to update products.
  """
  renameProductAttributeValue(
    """The value and its new name."""
    input: RenameProductAttributeValueInput!
  ): ProductAttributeChangeResult!
  """
  Requires permission `settings:integration:update`.
  
  Set the order of the delivery partners, top first. The order drives the partner list, the automatic partner-order rule and every tie-break. Partners you leave out keep their relative order after the listed ones. At most 200 partners, and one cannot appear twice.
  """
  reorderDeliveryPartners(
    """The delivery partner configuration IDs in the new order."""
    ids: [ID!]!
  ): [DeliveryPartnerConfigGql!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Re-add every line from a past order onto the shared cart. Returns a SUMMARY, not a bare cart: reorder re-prices at today's catalogue, so the buyer has to be told which lines changed price and which could not be re-added at all.
  """
  reorderFromOrder(
    """The ID of the order."""
    orderId: ID!
  ): MobileReorderResult!
  """
  Requires permission `settings:appearance:update`.
  
  Set the order of the organization's menus from a list of menu IDs. Every ID must belong to the organization. Needs the appearance settings update permission.
  """
  reorderMenus(
    """The menu IDs in the new order."""
    menuIds: [ID!]!
  ): [Menu!]!
  """
  Requires permission `visits:visit:execute`.
  
  Reorder the signed-in rep's remaining planned stops for today. Returns the whole day's visits.
  """
  reorderVisits(
    """The IDs of today's planned visits in the new order."""
    visitIds: [ID!]!
  ): [Visit!]!
  """
  Requires at least one of the permissions `settings:documents:update` or `settings:email:update`.
  
  Operator-triggered redo of a dead-lettered (FAILED) document delivery.
  """
  replayDocumentDelivery(
    """The ID of the document delivery."""
    id: String!
  ): OutboxDeliveryRow!
  """
  Requires permission `settings:webhooks:update`.
  
  Sends a finished delivery again, from the first attempt, with the stored payload. A delivery that is still queued cannot be replayed. Requires permission to update webhooks.
  """
  replayWebhookDelivery(
    """The ID of the webhook delivery."""
    id: ID!
  ): WebhookDelivery!
  """
  Requires a customer (portal or buyer app) session.
  
  Buyer-initiated account closure. Revokes access immediately (status INACTIVE + deletedAt) and signs out every device; staff complete the personal-data erasure within 30 days. Orders/invoices are retained as statutory records. Required by the Play account-deletion policy and App Store guideline 5.1.1(v).
  """
  requestAccountDeletion(
    """Why the account is being deleted."""
    reason: String
  ): Boolean!
  """
  Public: no authentication required.
  
  Sends a 6-digit OTP to an existing, active customer's email.
  """
  requestCustomerOtp(
    """The details of the request customer otp request."""
    input: RequestCustomerOtpInput!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Step 1 of changing the buyer's OWN email: send a 6-digit OTP to the NEW address. Authenticated (NOT @Public) — the org comes from the caller's token, and the code proves they control the address they are moving to. Rejects an address already used by another user in the org, and the caller's current address. Distinct from `requestEmailOtp`, which gates on `assertBuyerLoginAllowed` and would reject a brand-new address on self-registration-off tenants.
  """
  requestEmailChangeOtp(
    """The details of the request email change otp request."""
    input: RequestEmailChangeOtpInput!
  ): Boolean!
  """
  Public: no authentication required.
  
  Send a 6-digit OTP to the given email.
  """
  requestEmailOtp(
    """The details of the request email otp request."""
    input: RequestEmailOtpInput!
  ): Boolean!
  """
  Public: no authentication required.
  
  Emails a one-time sign-in code, valid for 5 minutes, to a staff account. It returns true whether or not an account matches, so the response does not reveal which email addresses have accounts. Rate-limited per IP address. No sign-in needed.
  """
  requestLoginOtp(
    """
    The email address and the organization subdomain. When the subdomain is omitted, the request host decides the organization.
    """
    requestOtpInput: RequestOtpInput!
  ): Boolean!
  """
  Public: no authentication required.
  
  Step 1 of registering an organization by email: sends a verification code to the address. Rate-limited per IP address. No sign-in needed.
  """
  requestRegistrationOtp(
    """The email address to send the code to."""
    input: RequestRegistrationOtpInput!
  ): RequestRegistrationOtpResponse!
  """
  Public: no authentication required.
  
  Send an OTP via WhatsApp (stub — not configured).
  """
  requestWhatsAppOtp(
    """The details of the request whats app otp request."""
    input: RequestWhatsAppOtpInput!
  ): Boolean!
  """
  Requires permission `visits:visit:execute`.
  
  Moves one of the signed-in rep's visits to another day. A planned visit joins that day's plan for the same rep. It is refused once the visit has a check-in or is completed or cancelled. Requires permission to run visits.
  """
  rescheduleVisit(
    """The day to move the visit to."""
    newDate: DateTime!
    """The ID of the visit."""
    visitId: ID!
  ): Visit!
  """
  Requires the permissions `settings:organization:update` and `settings:system:update`.
  
  Deletes all of the organization's transactional and seeded data for good, in one step: all of it goes or none. The organization, users, roles, currencies, taxes, units of measure, warehouses, email configuration and appearance are kept. Needs both settings:organization:update and settings:system:update. The reset is audited.
  """
  resetOrganizationData(
    """
    The organization's exact name, typed to confirm. Not case sensitive; a mismatch is refused.
    """
    confirmationName: String!
  ): ResetDataResult!
  """
  Public: no authentication required.
  
  Sets a new password using the token from the emailed reset link. The token works once, and the request fails if it is invalid or expired. All of the user's sessions end. Rate-limited per IP address. No sign-in needed.
  """
  resetPassword(
    """The token from the reset link and the new password."""
    resetPasswordInput: ResetPasswordInput!
  ): Boolean!
  """
  Requires permission `products:brand:create`.
  
  Match-or-create a brand by name (used when applying an AI-suggested new brand). Needs the brands create permission.
  """
  resolveEnrichedBrand(
    """The brand name found during enrichment."""
    name: String!
  ): ResolvedBrand!
  """
  Requires permission `sales:shipment:update`.
  
  Resolves a booking that needs checking (status BOOKING_ORPHANED), once you have checked with the courier. `CONFIRM_BOOKED` records that the courier holds the booking, optionally with its tracking number, and `MARK_CANCELLED` records that you cancelled it there. It never calls the carrier. A shipment in any other status is refused. Needs the delivery partners feature on your plan and the shipment update permission.
  """
  resolveOrphanedShipment(
    """The ID of the shipment."""
    id: ID!
    """The details of the resolve orphaned shipment request."""
    input: ResolveOrphanedShipmentInput!
  ): ShipmentGql!
  """
  Requires permission `settings:role:update`.
  
  Restores a soft-deleted role. Refused if the role is not deleted. Needs settings:role:update.
  """
  restoreRole(
    """The ID of the role."""
    id: ID!
  ): Role!
  """
  Requires permission `catalog:copilot:chat`.
  
  Resumes one of the caller's own paused scheduled copilot tasks and clears its last error. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  resumeCopilotScheduledJob(
    """The ID of the scheduled task."""
    id: ID!
  ): CopilotScheduledJobType!
  """
  Requires permission `sales:sales_order:allocate`.
  
  Re-reserve the backordered part of confirmed orders after stock arrives. Send orderId to retry one order and warehouseId to limit the retry to one warehouse; with neither, it retries across the organization. Any part that still cannot be covered stays backordered. Needs the sales order allocate permission.
  """
  retryBackorderReservations(
    """
    The ID of one sales order to retry. Omit to retry every order with a backorder.
    """
    orderId: ID
    """Limit the retry to this warehouse."""
    warehouseId: ID
  ): BackorderRetryResult!
  """
  Requires permission `catalog:copilot:apply`.
  
  Re-applies only the failed items of a PARTIAL batch (derived idempotency key per retry).
  """
  retryFailedProposalItems(
    """The ID of the batch."""
    batchId: ID!
    """The ID of the proposal."""
    proposalId: ID!
    """The ID of the Copilot session."""
    sessionId: ID!
  ): ApplyProposalResult!
  """
  Requires at least one of the permissions `settings:organization:update` or `settings:tenant:update`.
  
  Resets a custom hostname to pending and asks for its setup again, for example after a failure. Only custom hostnames qualify. Needs settings:organization:update, or settings:tenant:update.
  """
  retryOrganizationDomainProvisioning(
    """The ID of the domain."""
    id: ID!
  ): OrganizationDomain!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve` or `purchase:purchase_order:approve`.
  
  Returns a pending approval request to its requester with a reason (1 to 500 characters), for example to fix the document first. A returned request is final. Same signer rules as approveControlRequest.
  """
  returnControlRequest(
    """The approval request's ID."""
    id: ID!
    """Why, 1 to 500 characters."""
    reason: String!
  ): ControlApprovalRequest!
  """
  Requires at least one of the permissions `payments:payment:reverse` or `purchase:payment:reverse`.
  
  Reverses selected allocations of a payment: each affected invoice's paid amount goes back down and it owes the money again. The original allocation is kept and a negative counter-entry records the reversal. At least one allocation ID is required.
  """
  reversePaymentAllocations(
    """The payment and the allocations to reverse."""
    input: ReversePaymentAllocationsInput!
  ): Payment!
  """
  Requires permission `catalog:copilot:chat`.
  
  Undo one write Minori's memory capture made for the CALLER, by the factId and writtenAt a memory frame reported. Returns false when there is nothing to undo: the fact changed since, is not the caller's, was not captured, was forgotten, or was already undone.
  """
  revertCopilotMemoryWrite(
    """The key of the fact."""
    factId: String!
    """The time the write was recorded, in milliseconds since 1970."""
    writtenAt: Float!
  ): Boolean!
  """
  Requires permission `sales:sales_order:ship`.
  
  Restore the customer's original courier choice and price on an order. Same rules as changeOrderCourier.
  """
  revertOrderCourier(
    """
    The version of the record you last read. The change is refused if someone else changed it since.
    """
    expectedVersion: Int
    """The ID of the sales order."""
    salesOrderId: ID!
  ): SalesOrder!
  """
  Requires an authenticated session.
  
  Ends all of the signed-in user's sessions except the current one.
  """
  revokeAllSessions: Boolean!
  """
  Requires at least one of the permissions `settings:api:delete` or `settings:tenant:update`.
  
  Revoke an API key permanently. Requires permission to delete API keys or update tenant settings.
  """
  revokeApiKey(
    """The ID of the API key."""
    id: String!
  ): Boolean!
  """
  Requires at least one of the permissions `notifications:push-token:manage` or `settings:api:update`.
  
  Disconnect one MCP app from your account in this organization: every access and refresh token it holds for you is revoked at once. Returns the number of tokens revoked.
  """
  revokeConnectedApp(
    """The ID of the connected app."""
    clientId: String!
  ): Int!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:delegation:manage`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve` or `purchase:purchase_order:approve`.
  
  Revokes a cover now. The person covered, whoever set it, or a holder of approvals:delegation:manage may revoke it.
  """
  revokeControlApprovalDelegation(
    """The cover's ID."""
    id: ID!
  ): ControlApprovalDelegation!
  """
  Requires an authenticated session.
  
  Ends one of the signed-in user's own sessions. Fails if the session is not theirs.
  """
  revokeSession(
    """The ID of the session."""
    sessionId: String!
  ): Boolean!
  """
  Requires an authenticated session.
  
  Removes trust from one of the signed-in user's devices.
  """
  revokeTrustedDevice(
    """The ID of the trusted device."""
    deviceId: String!
  ): Boolean!
  """
  Requires permission `settings:api:update`.
  
  Admin: disconnect every MCP app from one user of your organization. Returns the number of tokens revoked.
  """
  revokeUserConnectedApps(
    """The ID of the user whose connected apps are revoked."""
    userId: String!
  ): Int!
  """
  Requires permission `catalog:copilot:rollback`.
  
  "Undo this import": restores the exact prior state of an applied batch.
  """
  rollbackCatalogBatch(
    """The ID of the batch."""
    batchId: ID!
  ): RollbackBatchResult!
  """
  Requires permission `products:import:rollback`.
  
  Reference-guarded rollback of a COMPLETED import — unreferenced variants it created are deleted, referenced or stocked ones deactivated; updates are not reverted (notRevertedCount).
  """
  rollbackProductImport(
    """The ID of the import."""
    importId: String!
  ): ProductImportRollbackResult!
  """
  Requires permission `storefront:storefront:publish`.
  
  Point the storefront at an earlier published version, so buyers see it again. The version is checked again first.
  """
  rollbackStorefrontTheme(
    """The ID of the theme version."""
    versionId: ID!
  ): StorefrontThemeVersionSummary!
  """
  Requires permission `settings:webhooks:update`.
  
  Issues a new signing secret for a webhook endpoint and returns it once. The old secret stops verifying immediately. Requires permission to update webhooks.
  """
  rotateWebhookEndpointSecret(
    """The ID of the webhook endpoint."""
    id: ID!
  ): WebhookEndpointWithSecret!
  """
  Requires permission `storefront:storefront:update`.
  
  Decide whether one theme-editor chat message asks for a page (several library sections, startStorefrontPageGeneration) or one section (startStorefrontSectionGeneration). A model decides (the typed decider, else a small model), never a word list. Synchronous; writes nothing; meters AI credits.
  """
  routeStorefrontRequest(
    """
    The seller's chat message, where it goes, the page it is for and how many images go with it.
    """
    input: RouteStorefrontRequestInput!
  ): StorefrontRequestRoute!
  """
  Requires permission `catalog:copilot:chat`.
  
  Queues an immediate run of one of the caller's own scheduled copilot tasks, even when it is paused, and returns it marked as queued. Limited to 10 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  runCopilotScheduledJobNow(
    """The ID of the scheduled task."""
    id: ID!
  ): CopilotScheduledJobType!
  """
  Restricted to platform staff.
  
  Platform only. Carry each named organization's Home CMS into its storefront theme and publish it as version 1. An organization with a theme or a published version is skipped; one with no Home CMS rows gets nothing written.
  """
  runStorefrontThemeCutover(
    """The IDs of the organizations."""
    organizationIds: [ID!]!
  ): StorefrontCutoverReport!
  """
  Requires permission `settings:controls:manage`.
  
  Creates a control (it starts in observe unless sent as off) or updates one's rule. Refused with CONTROL_RULE_INVALID when the rule fails validation, or CONTROL_NO_ELIGIBLE_APPROVER when nobody other than you could approve it. Requires settings:controls:manage.
  """
  saveControl(
    """The control to create or update."""
    input: SaveControlInput!
  ): ControlRuleType!
  """
  Requires permission `settings:organization:update`.
  
  Adds a playbook rule, or edits an existing one when its key is given. The playbook is the organization's standing instructions to the copilot: at most 12 rules, each 1 to 200 characters. A new rule takes the lowest free number. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to update organization settings.
  """
  saveCopilotPlaybookRule(
    """The key of the rule to edit. Omit it to add a new rule."""
    key: String
    """The rule's wording, 1 to 200 characters."""
    text: String!
  ): CopilotMemoryFactType!
  """
  Requires permission `settings:organization:update`.
  
  Create or replace a saved prompt, returning the organization's full list. The slug is the handle and re-using one overwrites that template.
  """
  saveCopilotPromptTemplate(
    """The text of the template."""
    body: String!
    """
    The slug that identifies the template. An existing slug is overwritten.
    """
    slug: String!
    """The new title."""
    title: String!
  ): [CopilotPromptTemplateType!]!
  """
  Requires permission `catalog:copilot:chat`.
  
  Saves the import rules for one supplier: a column map, a price rule and a minimum order quantity rule. There is one rule per supplier, and saving again for the same supplier replaces it. Supplier names that differ only in case or punctuation are the same supplier. Limited to 20 requests a minute. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  saveCopilotSupplierRule(
    """
    The supplier name and the optional column map, price rule and minimum order quantity rule.
    """
    input: SaveCopilotSupplierRuleInput!
  ): SupplierRuleType!
  """
  Requires permission `sales:quote:update`.
  
  Creates an email draft, or updates one of the caller's own when an ID is given. A draft belongs to its author: another user's draft, or an unknown ID, is treated as missing. Requires permission to update quotes.
  """
  saveDraft(
    """
    The draft's recipients, subject and body, the quote or order it relates to, and its ID when updating.
    """
    input: SaveDraftInput!
  ): EmailDraft!
  """
  Requires permission `products:import:stage`.
  
  S2.2 — create (no id) or update (id) a per-supplier mapping profile. Enforces per-tenant name uniqueness.
  """
  saveImportMappingProfile(
    """The details of the import mapping profile to save."""
    input: SaveImportMappingProfileInput!
  ): ImportMappingProfile!
  """
  Requires permission `storefront:storefront:update`.
  
  Save the storefront editor's draft. Buyers do not see it until it is published. Refused when it is not a storefront document, is over the size limit, or breaks the store page rule.
  """
  saveStorefrontDraft(
    """The details of the storefront draft to save."""
    input: SaveStorefrontDraftInput!
  ): StorefrontDraftSaved!
  """
  Requires at least one of the permissions `purchase:debit_note:update` or `sales:credit_note:update`.
  
  Schedules the pickup of a returned shipment. Without `delivery` it only records the pickup details. With `delivery` it books a courier that is set up for returns; the booking is all-or-nothing and shows the carrier's own error if it fails, and it also needs the shipment create permission. A carrier's "collected" update moves the return to IN_TRANSIT. Needs the update permission of the return's direction.
  """
  scheduleReturnPickup(
    """The details of the schedule pickup request."""
    input: SchedulePickupInput!
    """The ID of the return."""
    returnId: String!
  ): ReturnResponse!
  """
  Requires permission `settings:appearance:create`.
  
  Adds the standard set of menus the organization is missing, skipping any whose name already exists, without regard to case or padding. Needs the appearance settings create permission.
  """
  seedDefaultMenus: Boolean!
  """
  Requires the permissions `products:tax:create` and `settings:tenant:update`.
  
  Adds the built-in standard tax rates for the countries named, or for every supported country when none are named, and returns the rates created. Needs both the tax create and the tenant settings update permissions.
  """
  seedGlobalTaxRates(
    """
    The country codes to add rates for. Omit it to add the rates of every supported country.
    """
    countries: [String!]
  ): [TaxRate!]!
  """
  Requires permission `inventory:stock_level:create`.
  
  Creates a zero-quantity stock line for every active product variant that has none in a warehouse, so all products appear in stock levels. Without `warehouseId` it uses the default warehouse. Running it again skips lines that already exist. Needs the stock level create permission.
  """
  seedInventory(
    """Only this warehouse. Omit for all warehouses."""
    warehouseId: ID
  ): SeedInventoryResponse!
  """
  Requires a tenant administrator.
  
  Loads sample data into the organization, using the organization's own country and currency. A failure is reported in the returned message rather than as an error. Only admins and owners can do this.
  """
  seedOrganizationData: SystemActionResponse!
  """
  Requires permission `settings:permission:create`.
  
  Inserts any missing permissions from the built-in catalogue and skips ones that already exist. Returns true on success. Needs settings:permission:create.
  """
  seedPermissions: Boolean!
  """
  Requires permission `sales:credit_note:update`.
  
  Emails a credit note to the customer. A `customerEmail` you pass wins; otherwise the customer's email on record is used. A failure is returned as `success` false with a message rather than as an error. A user cannot email a note they cannot open.
  """
  sendCreditNoteEmail(
    """The ID of the credit note."""
    creditNoteId: ID!
    """The email address to send to. Omit to use the customer on the record."""
    customerEmail: String
  ): SendEmailResult!
  """
  Requires permission `communications:message:send`.
  
  Sends one customer a WhatsApp reminder for an attention-list item, through the consent and send rules. Each invoice or quote is reminded at most once per cooldown period, and the customer must be in the caller's own book. Limited to 20 requests a minute. Requires permission to send messages.
  """
  sendCustomerReminder(
    """The customer and the kind of reminder."""
    input: CustomerReminderInput!
  ): CustomerReminderResultGql!
  """
  Requires permission `communications:message:send`.
  
  Sends the same kind of reminder to several of the caller's customers at once. Each customer is checked on its own, and a customer that cannot be reminded is skipped with a reason. Limited to 5 requests a minute. Requires permission to send messages.
  """
  sendCustomerReminders(
    """The customers and the kind of reminder."""
    input: CustomerRemindersInput!
  ): CustomerRemindersResultGql!
  """
  Requires permission `purchase:debit_note:update`.
  
  Emails a debit note to the supplier. A `customerEmail` you pass (it is the recipient address, here the supplier's) wins; otherwise the supplier's active email contact is used, and with neither the call reports that no address is on file. A failure is returned as `success` false with a message rather than as an error. A user cannot email a note they cannot open.
  """
  sendDebitNoteEmail(
    """The email address to send to. Omit to use the customer on the record."""
    customerEmail: String
    """The ID of the debit note."""
    debitNoteId: ID!
  ): SendEmailResult!
  """
  Requires at least one of the permissions `payments:invoice:send` or `purchase:purchase_invoice:send`.
  
  Emails an invoice to the customer's email address on record. Refused when the customer has no email address. A user cannot email an invoice they cannot open.
  """
  sendInvoiceEmail(
    """
    The recipient's email address. When omitted the customer's email contact on file is used.
    """
    customerEmail: String
    """The ID of the invoice to email."""
    invoiceId: ID!
  ): Boolean!
  """
  Requires at least one of the permissions `payments:invoice:send` or `purchase:purchase_invoice:send`.
  
  Emails the customer a payment reminder for an invoice. Refused for an invoice that is already fully paid, and when the customer has no email address.
  """
  sendInvoiceReminder(
    """
    The recipient's email address. When omitted the customer's email contact on file is used.
    """
    customerEmail: String
    """The ID of the invoice the reminder is about."""
    invoiceId: ID!
  ): Boolean!
  """
  Requires permission `users:user:update`.
  
  Emails an active staff user in your organization a link to set their password: an invite link (valid 24 hours) if they have no password yet, a reset link (valid 1 hour) if they do. The administrator never sets, sees or receives the password or the link. You need every permission the target user holds, a refusal is returned as an error, and one link can be sent to a user per minute. Returns true once the link is sent. Needs users:user:update.
  """
  sendPasswordResetLink(
    """The ID of the user."""
    userId: ID!
  ): Boolean!
  """
  Requires at least one of the permissions `payments:payment:send` or `purchase:payment:send`.
  
  Emails a receipt for a payment. An address you pass wins; otherwise the partner's active email contact is used. Refused when no email address is found. A user cannot email a receipt for a payment they cannot open.
  """
  sendPaymentReceiptEmail(
    """The recipient's email address."""
    customerEmail: String
    """The ID of the payment the receipt is for."""
    paymentId: ID!
  ): Boolean!
  """
  Requires permission `purchase:purchase_order:update`.
  
  Emails a purchase order to the supplier and returns `success` with a message. Needs the purchase order update permission and the purchase orders feature on your plan.
  """
  sendPurchaseOrderEmail(
    """The message text. Omit for the default text."""
    message: String
    """The ID of the purchase order."""
    purchaseOrderId: ID!
    """The email address to send to."""
    recipientEmail: String!
    """The email subject. Omit for the default subject."""
    subject: String
  ): SendEmailResult!
  """
  Requires permission `sales:quote:update`.
  
  Email a quote to a customer address with the quote PDF attached. Optional subject, a custom message, and CC addresses separated by commas or semicolons. Recipients are screened for deliverability before sending.
  """
  sendQuoteEmail(
    """CC addresses, separated by commas or semicolons."""
    ccEmail: String
    """A message to include in the email body."""
    customMessage: String
    """The recipient's email address."""
    customerEmail: String!
    """The ID of the quote to email."""
    quoteId: ID!
    """Email subject. A default is used when omitted."""
    subject: String
  ): SendQuoteEmailResult!
  """
  Requires permission `sales:quote:update`.
  
  Enqueue a quote email onto the durable delivery pipeline (PDF render + send happen in the background worker with retry/backoff) instead of sending inline.
  """
  sendQuoteEmailDurable(
    """A message to include in the email body."""
    customMessage: String
    """The ID of the quote to email."""
    quoteId: String!
    """The recipient's email address."""
    recipient: String!
  ): Boolean!
  """
  Requires permission `sales:quote:update`.
  
  Email a quote through Postmark with the quote PDF attached. Send To, Cc and Bcc lists of up to 20 addresses each; at least one To recipient is required. Every address is screened for deliverability before sending.
  """
  sendQuoteEmailPostmark(
    """The quote, its recipients and the message to send."""
    input: SendQuoteEmailInput!
  ): SendQuoteEmailResult!
  """
  Requires permission `sales:quote:update`.
  
  Send a reply to a customer's email on a quote. The email being replied to is required; the recipient defaults to the original sender and the subject to Re: followed by the original subject.
  """
  sendQuoteReply(
    """The reply to send."""
    input: SendQuoteReplyInput!
  ): SendQuoteEmailResult!
  """
  Requires permission `sales:sales_order:send`.
  
  Email a sales order to a customer address with the order PDF. Optional subject, CC addresses and a custom message. Recipients are screened for deliverability before sending.
  """
  sendSalesOrderEmail(
    """CC addresses, separated by commas or semicolons."""
    ccEmail: String
    """A message to include in the email body."""
    customMessage: String
    """The recipient's email address."""
    customerEmail: String!
    """The ID of the sales order to email."""
    salesOrderId: ID!
    """Email subject. A default is used when omitted."""
    subject: String
  ): SendEmailResult!
  """
  Requires permission `sales:sales_order:send`.
  
  Email the customer a payment reminder for an order. A valid customer email is required.
  """
  sendSalesOrderPaymentReminder(
    """The recipient's email address."""
    customerEmail: String!
    """The ID of the sales order the reminder is about."""
    salesOrderId: ID!
  ): SendEmailResult!
  """
  Requires permission `sales:sales_order:send`.
  
  Send a threaded reply on an order's email conversation.
  """
  sendSalesOrderReply(
    """The reply to send."""
    input: SendSalesOrderReplyInput!
  ): SendEmailResult!
  """
  Requires permission `visits:journey-plan:manage`.
  
  Sends a message about one stop to the rep it is assigned to. It appears in the rep's notifications and on that visit's detail screen. An empty message is refused. Requires permission to manage journey plans.
  """
  sendVisitMessage(
    """The message text."""
    message: String!
    """The ID of the visit."""
    visitId: ID!
  ): Boolean!
  """
  Requires permission `settings:webhooks:update`.
  
  Queues a test event to a webhook endpoint, even if the endpoint is inactive, and returns the delivery so its outcome can be followed. Requires permission to update webhooks.
  """
  sendWebhookTestEvent(
    """The ID of the webhook endpoint."""
    endpointId: ID!
  ): WebhookDelivery!
  """
  Requires permission `settings:integration:update`.
  
  Sends a real WhatsApp test message to a phone number for one trigger, using a provider, so a template can be checked. Requires permission to update integrations.
  """
  sendWhatsAppTestMessage(
    """
    The phone number to send to, the trigger, an optional provider and the values for the message body.
    """
    input: SendWhatsAppTestMessageInput!
  ): WhatsAppTestResultGql!
  """
  Requires a customer (portal or buyer app) session.
  
  Records the active address server-side for analytics + cart restoration.
  """
  setActiveAddress(
    """The ID of the address."""
    addressId: ID!
  ): Boolean!
  """
  Requires permission `settings:tenant:update`.
  
  Sets the organization's base currency. It is refused once the organization has posted transactions or an administrator has locked the base currency. Requires permission to update tenant settings.
  """
  setBaseCurrency(
    """The ID of the currency to make the base currency."""
    currencyId: String!
  ): Currency!
  """
  Requires a customer (portal or buyer app) session.
  
  activate/deactivate a branch (CUSTOMER_ADMIN only). The response carries pendingApprovalCount for the deactivation warning (EDGE #4).
  """
  setBranchActive(
    """The ID of the address."""
    addressId: ID!
    "Whether the record is active."
    isActive: Boolean!
  ): CustomerBranch!
  """
  Requires a customer (portal or buyer app) session.
  
  flag/un-flag an existing same-partner address as a branch (CUSTOMER_ADMIN only). Flagging requires a unique label (BRANCH_LABEL_REQUIRED / BRANCH_LABEL_CONFLICT); un-flagging runs the in-use guard and nulls the order limit.
  """
  setBranchFlag(
    """The ID of the address."""
    addressId: ID!
    """True to mark the address as a branch, false to unmark it."""
    isBranch: Boolean!
  ): CustomerBranch!
  """
  Requires a customer (portal or buyer app) session.
  
  set/clear the branch order-value ceiling (CUSTOMER_ADMIN only). Null = unlimited; a non-positive value is rejected.
  """
  setBranchLimit(
    """The ID of the address."""
    addressId: ID!
    """The most a branch may order in one order. Send null for no limit."""
    orderLimit: Float
  ): CustomerBranch!
  """
  Requires a customer (portal or buyer app) session.
  
  Set free-text delivery instructions on the cart (max 200 chars).
  """
  setCartDirections(
    """The fields of the cart directions to change."""
    input: SetCartDirectionsInput!
  ): MobileCart!
  """
  Requires permission `commissions:commission:update`.
  
  Sets the commission rate of one role, between 0 and 100 percent. Every role needs its own rate: an active rate above zero cannot equal another role's active rate. Requires permission to update commissions.
  """
  setCommissionRoleRate(
    """The role, the rate and whether it is active."""
    input: SetCommissionRoleRateInput!
  ): CommissionRoleRate!
  """
  Requires permission `settings:controls:manage`.
  
  Switches a control off, to observe or to enforce. Turning it on re-runs the setup check; switching to enforce needs a reason, which the settings history keeps. Requires settings:controls:manage.
  """
  setControlMode(
    """The control and its new mode."""
    input: SetControlModeInput!
  ): ControlRuleType!
  """
  Requires permission `settings:controls:manage`.
  
  Turns the controls kill switch on (every enforced control only observes until released) or off. A reason is required either way; the change is kept in the settings history and the activity log. Requires settings:controls:manage.
  """
  setControlsKillSwitch(
    """On or off, and why."""
    input: SetControlsKillSwitchInput!
  ): ControlsKillSwitchType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Turn the CALLER'S own auto mode on or off: low-tier cards Minori asks about are approved without asking. Never applies at medium or above.
  """
  setCopilotAutoApproveLow(
    """True to approve low-risk Copilot actions automatically."""
    enabled: Boolean!
  ): CopilotApprovalRulesType!
  """
  Requires permission `settings:organization:update`.
  
  Set this organization's Minori autonomy cap. `level: null` clears it, which resolves back to `full`. Existing proposal cards are NOT deleted by a tightening — they simply stop being applicable, which the apply path refuses with the reason.
  """
  setCopilotAutonomyLevel(
    """The autonomy level. Send null to remove the cap."""
    level: String
  ): CopilotAutonomyCapType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Turn Minori's memory on or off. `enabled: null` clears the caller's own override so the organization default applies again. Off stops both reading and writing; it does NOT delete existing facts — clearCopilotMemory does that.
  """
  setCopilotMemoryEnabled(
    """
    True to turn Copilot memory on, false to turn it off. Send null to leave it unchanged.
    """
    enabled: Boolean
    """True to let Copilot learn from the user's activity."""
    learning: Boolean! = false
    """
    True to change the setting for the whole organization instead of the caller.
    """
    organizationWide: Boolean! = false
  ): CopilotMemorySwitchType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Turn "don't ask again for low-tier cards in this chat" on or off for one of the CALLER'S sessions. Never applies at medium or above.
  """
  setCopilotSessionApprovalRule(
    """True to apply the approval rule to this session."""
    enabled: Boolean!
    """The ID of the Copilot session."""
    sessionId: ID!
  ): CopilotApprovalRulesType!
  """
  Requires permission `settings:organization:update`.
  
  Set how many Minori turns each of this organization's buyers may start per UTC day, from 0 (buyers off) to 1000. `turns: null` clears it back to the platform default.
  """
  setCopilotShopperDailyTurns(
    """The daily turn limit per shopper. Send null to remove the limit."""
    turns: Int
  ): CopilotShopperTurnCapType!
  """
  Requires a customer (portal or buyer app) session.
  
  set an approver's scope (CUSTOMER_ADMIN only) — COMPANY (all branches; clears grants) or BRANCH (≥1 branch address id; full-array replace of grants).
  """
  setCustomerApproverScope(
    """The fields of the customer approver scope to change."""
    input: SetCustomerApproverScopeInput!
  ): CustomerApproverScopeResult!
  """
  Requires permission `commissions:commission:update`.
  
  Sets the commission rate for one customer and whether it is active. The customer must belong to the organization. Requires permission to update commissions.
  """
  setCustomerCommissionRate(
    """The customer, the rate and whether it is active."""
    input: SetCustomerCommissionRateInput!
  ): CustomerCommissionRate!
  """
  Requires at least one of the permissions `settings:customer_tiers:update` or `settings:tenant:update`.
  
  Pins a customer to a tier, which locks it against automatic changes. With no tier given it clears the lock and hands the customer back to automatic tiering. A tier that is not in the ladder is refused. Requires permission to update customer tier or tenant settings.
  """
  setCustomerTierOverride(
    """The customer and the tier to pin. Omit the tier to clear the lock."""
    input: SetCustomerTierOverrideInput!
  ): CustomerTierStatus!
  """
  Requires at least one of the permissions `settings:customer_tiers:update` or `settings:tenant:update`.
  
  Switches the customer tiers module on or off. Only the switch changes: the saved tiers and every customer's tier are kept, so switching back on restores them. Requires permission to update customer tier or tenant settings.
  """
  setCustomerTiersModuleEnabled(
    """True to switch the module on, false to switch it off."""
    enabled: Boolean!
  ): CustomerTierConfig!
  """
  Requires permission `payments:bank-account:update`.
  
  Makes a bank account the default for its currency and turns it on if it was off. The other accounts in the same currency lose the default flag. Requires permission to update bank accounts.
  """
  setDefaultBankAccount(
    """The ID of the bank account."""
    id: ID!
  ): BankAccount!
  """
  Requires at least one of the permissions `settings:sales:update` or `settings:tenant:update`.
  
  Makes one payment term the organization's default for new documents, and clears the flag on the previous default so there is exactly one. An inactive term cannot be the default: reactivate it first.
  """
  setDefaultPaymentTerm(
    """The ID of the payment term to make the organization's default."""
    id: ID!
  ): PaymentTerm!
  """
  Requires at least one of the permissions `settings:regional:update` or `settings:tenant:update`.
  
  Makes a timezone the organization's default, taking the flag from the current default. Requires permission to update regional or tenant settings.
  """
  setDefaultTimezone(
    """The ID of the timezone."""
    id: String!
  ): Timezone!
  """
  Requires permission `settings:integration:update`.
  
  Turns a delivery partner on or off. Turning one on needs a verified connection and, for a provider that can only report status by webhook, a webhook that has already arrived. Needs the delivery partners plan feature and permission to update integrations.
  """
  setDeliveryPartnerEnabled(
    """True to turn the partner on, false to turn it off."""
    enabled: Boolean!
    """The ID of the delivery partner configuration."""
    id: ID!
  ): DeliveryPartnerConfigGql!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Registers the domain the organization sends document email from, replacing any earlier one, and returns the DNS records to publish. The domain stays pending until verifyEmailSenderDomain sees the records. Public mailbox domains and the platform's own domain are refused. Requires permission to update email settings.
  """
  setEmailSenderDomain(
    """
    The domain. A bare domain, an address or a web address are all accepted.
    """
    input: SetEmailSenderDomainInput!
  ): EmailSenderDomain!
  """
  Requires permission `settings:tenant:update`.
  
  Replaces the organization's whole set of product finders with the list given. Every flow is validated, and every category and brand it names must exist in the organization, before anything is saved, so a refused flow writes nothing. Requires permission to update tenant settings.
  """
  setGuidedFlows(
    """The complete list of guided flows to save."""
    input: SetGuidedFlowsInput!
  ): [GuidedFlow!]!
  """
  Requires permission `settings:tenant:update`.
  
  Set base currency (only before first transaction). Requires permission to update tenant settings.
  """
  setOrganizationBaseCurrency(
    """The fields of the base currency to change."""
    input: SetBaseCurrencyInput!
  ): Boolean!
  """
  Requires permission `communications:consent:update`.
  
  Marks a customer as do-not-market or clears the mark. Marketing messages are not sent to a marked customer. The customer must be in the caller's own book. Requires permission to update consent.
  """
  setPartnerDoNotMarket(
    """
    True to stop marketing messages to the customer, false to allow them again.
    """
    doNotMarket: Boolean!
    """The ID of the customer."""
    partnerId: ID!
  ): Boolean!
  """
  Requires permission `settings:integration:update`.
  
  Enables or disables one payment gateway. Enabling is refused until the API keys have been verified (`testPaymentGatewayConnection`) and a verified webhook event has been received from the provider. Gateways are independent: enabling one does not disable another.
  """
  setPaymentGatewayEnabled(
    """
    True to enable the gateway, false to disable it. Enabling needs valid keys and a reachable webhook.
    """
    enabled: Boolean!
    """The payment provider to enable or disable."""
    provider: PaymentGatewayProvider!
  ): PaymentGatewayConfigGql!
  """
  Requires at least one of the permissions `settings:organization:update` or `settings:tenant:update`.
  
  Makes a custom hostname the portal's main address. It must be custom and already active; only one is primary at a time. Needs settings:organization:update, or settings:tenant:update.
  """
  setPrimaryOrganizationDomain(
    """The ID of the domain."""
    id: ID!
  ): OrganizationDomain!
  """
  Requires permission `products:product:update`.
  
  Sets or clears the picture of one product attribute value; product finders then show it for that value. Requires permission to update products.
  """
  setProductAttributeValueImage(
    """The value and its new picture."""
    input: SetProductAttributeValueImageInput!
  ): ProductAttributeValue!
  """
  Requires permission `commissions:commission:update`.
  
  Sets a sales rep's default commission rate and whether it is active. Requires permission to update commissions.
  """
  setRepCommissionRate(
    """The rep, the default rate and whether the profile is active."""
    input: SetRepCommissionRateInput!
  ): RepCommissionProfile!
  """
  Requires permission `sales:sales_order:allocate`.
  
  Set the warehouse split for one order line. The split quantities must add up to the line quantity and every warehouse must be active. The split is honored at confirmation and reallocation.
  """
  setSalesOrderItemAllocations(
    """The order line and its warehouse split."""
    input: SetSalesOrderItemAllocationsInput!
  ): [SalesOrderItemAllocation!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Set the FULL list of addresses assigned to one team member (account owner only). Declarative: send the desired end state and it reconciles. An EMPTY list clears every assignment, which returns that member to seeing the whole account address book — a member with no assignments is unrestricted, not locked out. Returns the assigned ids.
  """
  setTeamMemberAddresses(
    """The IDs of the addresses."""
    addressIds: [ID!]!
    """The ID of the user."""
    userId: ID!
  ): [ID!]!
  """
  Requires permission `settings:integration:update`.
  
  Turns WhatsApp sending on or off for a provider. A connection must have been verified before it can be enabled, and enabling one provider turns the others off, since only one is enabled at a time. Requires permission to update integrations.
  """
  setWhatsAppEnabled(
    """True to turn sending on, false to turn it off."""
    enabled: Boolean!
    """
    The WhatsApp provider to use. Omit it to use the organization's enabled provider, else its most recently edited one.
    """
    provider: WhatsAppProvider
  ): WhatsAppConfigGql!
  """
  Requires an authenticated session.
  
  Starts two-factor setup for the signed-in user and returns a QR code and backup codes. The setup is kept for 10 minutes and nothing is turned on until enableTwoFactor succeeds.
  """
  setupTwoFactor: TwoFactorSetupResponse!
  """
  Requires permission `sales:sales_order:ship`.
  
  Ship an order, fully or partly. shippingData carries carrier and delivery details; shipping with a courier also needs the shipment-create permission.
  """
  shipSalesOrder(
    """The ID of the sales order."""
    id: ID!
    """
    What to ship and the carrier details. Omit to ship everything without a courier.
    """
    shippingData: ShipSalesOrderInput
  ): SalesOrder!
  """
  Requires permission `sales:sales_order:cancel`.
  
  Close the unfulfilled balance of a partly fulfilled order, leaving what has shipped as the final quantity. Needs the cancel permission.
  """
  shortCloseSalesOrder(
    """The ID of the sales order."""
    id: ID!
    """The reason and, optionally, which lines to close."""
    input: ShortCloseSalesOrderInput!
  ): SalesOrder!
  """
  Requires a customer (portal or buyer app) session.
  
  QA helper: walks an order through the happy-path statuses (CONFIRMED → OUT_FOR_DELIVERY → DELIVERED) with ~1s gaps. Disabled in production.
  """
  simulateOrderProgress(
    """The ID of the order."""
    orderId: ID!
  ): Boolean!
  """
  Requires permission `products:import:stage`.
  
  Enqueues the stage+validate background job once the file has been PUT to the presigned URL.
  """
  stageProductImport(
    """The ID of the import."""
    importId: String!
    """Column mapping that replaces the saved one for this import."""
    mappingOverride: JSON
  ): Boolean!
  """
  Requires permission `catalog:copilot:parse`.
  
  Parse an uploaded supplier file into the session IR (parse-once). Poll copilotJob for completion.
  """
  startCopilotParse(
    """The details of the copilot parse to start."""
    input: StartCopilotParseInput!
  ): CopilotJob!
  """
  Requires permission `catalog:copilot:parse`.
  
  Build an ImageSourcingProposal card for variants missing images (or an explicit variant scope).
  """
  startImageSourcing(
    """The details of the image sourcing to start."""
    input: StartImageSourcingInput!
  ): ImageSourcingStartResult!
  """
  Requires permission `products:product:update`.
  
  Start an async AI enrichment job (description, category, brand, public image candidates). Returns a jobId immediately — poll productEnrichmentJob(jobId) until COMPLETED/FAILED. Suggestion-only: writes nothing to the catalog. Meters AI credit usage when it runs. Needs the products update permission.
  """
  startProductEnrichment(
    """How deep the enrichment goes. Omit for the default."""
    depth: EnrichmentDepth = STANDARD
    """The ID of the product."""
    productId: ID!
  ): EnrichmentJob!
  """
  Requires permission `storefront:storefront:update`.
  
  Start an async job that turns the seller's request about the page on screen into checked edits to its values (copy, options, style, visibility, order, names, theme tokens) — never code — or, when the seller asks a question about the editor, the page or the buyer app, a short answer in words (result.answer) that changes nothing. Returns a jobId immediately — poll storefrontEditGenerationJob(jobId) until COMPLETED/FAILED/CANCELLED. Writes nothing: the editor applies the edits. Meters AI credits when it runs.
  """
  startStorefrontEditGeneration(
    """
    The seller's request, the editor's draft, the page on screen and what is selected.
    """
    input: StartStorefrontEditInput!
  ): StorefrontEditJob!
  """
  Requires permission `storefront:storefront:update`.
  
  Start an async job that plans a storefront page from the seller's sentence (and reference images): several built-in library sections filled with the store's own categories, brands and journey links. Returns a jobId immediately — poll storefrontPageGenerationJob(jobId) until COMPLETED/FAILED/CANCELLED. Writes nothing: the result is an import the theme editor proposes. Meters AI credits when it runs.
  """
  startStorefrontPageGeneration(
    """The details of the storefront page to start."""
    input: StartStorefrontPageInput!
  ): StorefrontPageJob!
  """
  Requires permission `storefront:storefront:update`.
  
  Start an async job that writes one storefront section (Liquid + CSS + editable fields) from the seller's sentence, or revises one (`revise`). Returns a jobId immediately — poll storefrontSectionGenerationJob(jobId) until COMPLETED/FAILED/CANCELLED. Writes nothing. Meters AI credits when it runs.
  """
  startStorefrontSectionGeneration(
    """The details of the storefront section to start."""
    input: StartStorefrontSectionInput!
  ): StorefrontSectionJob!
  """
  Requires permission `storefront:storefront:read`.
  
  An open storefront editor checks in (every 20 seconds, and when its unsaved state changes). Answers the other editors open now and when the draft was last saved; records nothing durable.
  """
  storefrontEditorHeartbeat(
    """
    This editor window: its own id, whether it has unsaved changes, and the page it shows.
    """
    input: StorefrontEditorHeartbeatInput!
  ): StorefrontEditorHeartbeat!
  """
  Requires a customer (portal or buyer app) session.
  
  Subscribe the buyer to a restock notification for a variant.
  """
  subscribeRestock(
    """The ID of the product variant."""
    variantId: ID!
  ): Boolean!
  """
  Requires an authenticated session.
  
  Signs the person in to another organization they belong to, matched by email, and returns new tokens for it. Refused when they have no account there.
  """
  switchOrganization(
    """The organization to switch to."""
    switchOrganizationInput: SwitchOrganizationInput!
  ): AuthResponse!
  """
  Requires permission `settings:integration:update`.
  
  Makes a real call to the delivery provider to check the stored credentials, records the result and returns the provider's exact rejection when it fails. A partner must pass this before it can be enabled. Needs the delivery partners plan feature and permission to update integrations.
  """
  testDeliveryPartnerConnection(
    """The ID of the delivery partner configuration."""
    id: ID!
  ): DeliveryPartnerVerification!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Sends a test email through the organization's configuration to the address given, from the company's own sender, and reports whether it worked. Requires permission to update email settings.
  """
  testEmailConfig(
    """The address to send the test to and an optional subject and message."""
    input: TestEmailConfigInput!
  ): TestEmailResult!
  """
  Requires permission `settings:integration:update`.
  
  Verifies the stored credentials for one provider by calling it. When the provider rejects them, the error carries the provider's own message. Verified keys are required before the gateway can be enabled.
  """
  testPaymentGatewayConnection(
    """The payment provider whose stored credentials to test."""
    provider: PaymentGatewayProvider!
  ): PaymentGatewayVerificationGql!
  """
  Requires permission `settings:integration:update`.
  
  Checks the stored API key against the WhatsApp provider and records the connection as verified when it works. Fails with the provider's reason when it does not. Requires permission to update integrations.
  """
  testWhatsAppConnection(
    """
    The WhatsApp provider to use. Omit it to use the organization's enabled provider, else its most recently edited one.
    """
    provider: WhatsAppProvider
  ): WhatsAppConfigGql!
  """
  Requires permission `settings:integration:update`.
  
  Switches an integration on or off, whichever it is not now. Switching on validates it first. Requires permission to update integrations.
  """
  toggleIntegrationEnabled(
    """The ID of the integration."""
    id: String!
  ): IntegrationSetting!
  """
  Requires at least one of the permissions `customers:customer:update` or `suppliers:supplier:update`.
  
  Adds a role to a partner that lacks it, or removes it from one that has it. Adding customer or supplier also creates the matching account. The last remaining role cannot be removed. Needs the update permission for each role the partner carries and for the toggled role.
  """
  togglePartnerRole(
    """The ID of the partner."""
    id: ID!
    """The role to add or remove."""
    role: PartnerRole!
  ): Partner!
  """
  Requires at least one of the permissions `settings:regional:update` or `settings:tenant:update`.
  
  Switches a timezone on or off, whichever it is not now. Requires permission to update regional or tenant settings.
  """
  toggleTimezoneActive(
    """The ID of the timezone."""
    id: String!
  ): Timezone!
  """
  Requires permission `inventory:stock_transfer:create`.
  
  Moves stock from one warehouse to another, for one or more items, in one call. The two warehouses must differ and both must exist, every item needs a variant, and each item needs enough available stock (on hand less reserved) in the source warehouse. An idempotency key makes a retry return the original movement. Needs the stock transfers feature on your plan and the stock transfer create permission.
  """
  transferInventory(
    """The details of the transfer inventory request."""
    input: TransferInventoryInput!
  ): StockMovement!
  """
  Requires permission `catalog:copilot:chat`.
  
  Bring one of the CALLER'S OWN archived chats back into their list.
  """
  unarchiveCopilotSession(
    """The ID of the Copilot session."""
    id: ID!
  ): CopilotSessionSummary!
  """
  Requires permission `notifications:push-token:manage`.
  
  Removes the push-notification token of one of the signed-in staff user's devices. Requires permission to manage push tokens.
  """
  unregisterMyPushToken(
    """The ID of the device to remove."""
    input: UnregisterPushTokenInput!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Unregister an Expo push token (called on logout or device wipe).
  """
  unregisterPushToken(
    """The details of the unregister push token request."""
    input: UnregisterPushTokenInput!
  ): Boolean!
  """
  Requires at least one of the permissions `settings:api:update` or `settings:tenant:update`.
  
  Updates the API settings: whether the API is on, its version, rate limits per minute and hour, API keys, allowed origins, and webhooks with their retry attempts. Returns the saved settings. Needs settings:api:update, or settings:tenant:update.
  """
  updateAPISettings(
    """The API settings to change; fields left out stay as they are."""
    input: APISettingsInput!
  ): [TenantSetting!]!
  """
  Requires at least one of the permissions `settings:accounting:update` or `settings:tenant:update`.
  
  Updates the accounting settings: fiscal year start, base currency, multi-currency, accounting method, tax calculation method, and the aging buckets and basis. Returns the saved settings. Needs settings:accounting:update, or settings:tenant:update.
  """
  updateAccountingSettings(
    """The accounting settings to change; fields left out stay as they are."""
    input: AccountingSettingsInput!
  ): [TenantSetting!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Update editable fields on an address owned by the buyer.
  """
  updateAddress(
    """The fields of the mobile address to change."""
    input: UpdateMobileAddressInput!
  ): Boolean!
  """
  Requires at least one of the permissions `settings:appearance:update` or `settings:tenant:update`.
  
  Updates the appearance settings: theme, colors, font, corner radius, animations, compact mode, sidebar behavior, breadcrumbs, logo and favicon. Returns the saved settings. Needs settings:appearance:update, or settings:tenant:update.
  """
  updateAppearanceSettings(
    """The appearance settings to change; fields left out stay as they are."""
    input: AppearanceSettingsInput!
  ): [TenantSetting!]!
  """
  Requires at least one of the permissions `settings:backup:update` or `settings:tenant:update`.
  
  Updates the backup settings: automatic backup, its frequency, time, retention, location, encryption and compression, and the notification email. Returns the saved settings. Needs settings:backup:update, or settings:tenant:update.
  """
  updateBackupSettings(
    """The backup settings to change; fields left out stay as they are."""
    input: BackupSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `payments:bank-account:update`.
  
  Updates a bank account's details. The running balance cannot be set here; use adjustBankAccountBalance. Requires permission to update bank accounts.
  """
  updateBankAccount(
    """The ID of the bank account."""
    id: ID!
    """The fields to change."""
    input: UpdateBankAccountInput!
  ): BankAccount!
  """
  Requires permission `products:brand:update`.
  
  Updates a brand. Changing the code to one already used by another brand is refused. Needs the brands update permission.
  """
  updateBrand(
    """The ID of the brand."""
    id: ID!
    """The fields to change on the brand."""
    updateBrandInput: UpdateBrandInput!
  ): Brand!
  """
  Requires a customer (portal or buyer app) session.
  
  Sets the quantity of one cart line. Pass the cart revision you last saw, and an operation ID so a retry applies once.
  """
  updateCartItem(
    """
    The cart line, its new quantity above zero, the expected cart revision and the operation ID.
    """
    input: UpdateCartItemInput!
  ): CartType!
  """
  Requires permission `categories:category:update`.
  
  Updates a category, including moving it under another parent, which also updates the level and path of its subcategories. A code already used by another active category is refused, and so is a parent that would create a loop. Requires permission to update categories.
  """
  updateCategory(
    """The ID of the category and the fields to change."""
    input: UpdateCategoryInput!
  ): Category!
  """
  Requires permission `categories:category:update`.
  
  Replaces a category's delivery defaults and keeps the category's other metadata. Needs the delivery partners plan feature and permission to update categories.
  """
  updateCategoryDeliveryDefaults(
    """The ID of the category."""
    categoryId: ID!
    """The delivery defaults to save for the category."""
    input: CategoryDeliveryDefaultsInput!
  ): CategoryDeliveryDefaults!
  """
  Requires an authenticated session.
  
  Changes a channel's name or description. Only an admin or manager, or an admin of that channel, can do this. Needs a signed-in user.
  """
  updateChatChannel(
    """The ID of the chat channel."""
    id: String!
    """The name or description to change."""
    input: UpdateChannelInput!
  ): ChatChannel!
  """
  Requires at least one of the permissions `settings:company:update` or `settings:tenant:update`.
  
  Updates the company settings: name, logo, timezone, language, postal address with coordinates, phone, email, website and tax ID. Returns the saved settings. Needs settings:company:update, or settings:tenant:update.
  """
  updateCompanySettings(
    """The company settings to change; fields left out stay as they are."""
    input: CompanySettingsInput!
  ): [TenantSetting!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Edit a person on the buyer's account.
  """
  updateContact(
    """The fields of the mobile contact to change."""
    input: UpdateMobileContactInput!
  ): MobileContact!
  """
  Requires an authenticated session.
  
  Changes a conversation's title. The caller must have access to the conversation. Needs a signed-in user.
  """
  updateConversation(
    """The ID of the conversation."""
    id: String!
    """The new title."""
    input: UpdateConversationInput!
  ): ChatConversation!
  """
  Requires permission `catalog:copilot:chat`.
  
  Inline edit of a card payload; revalidated and returned to PROPOSED.
  """
  updateCopilotProposal(
    """The fields of the copilot proposal to change."""
    input: UpdateCopilotProposalInput!
    """The ID of the Copilot session."""
    sessionId: ID!
  ): ProposalCardType!
  """
  Requires permission `sales:credit_note:update`.
  
  Changes a credit note. Only a DRAFT or PENDING note that has not been applied to any invoice can be edited; any other status is refused. The same credit limit against the invoice applies as on creation.
  """
  updateCreditNote(
    """The ID of the credit note."""
    id: ID!
    """The fields of the credit note to change."""
    input: UpdateCreditNoteInput!
  ): CreditNote!
  """
  Requires permission `platform:currency:manage`.
  
  Edits a currency's master record. Currencies are shared by every organization, so this needs the platform permission to manage currencies, which only platform administrators hold.
  """
  updateCurrency(
    """The ID of the currency."""
    id: String!
    """The fields to change."""
    input: UpdateCurrencyInput!
  ): Currency!
  """
  Requires permission `customers:customer:update`.
  
  Updates a customer. Needs the customers update permission.
  """
  updateCustomer(
    """The ID of the customer and the fields to change."""
    updateCustomerInput: UpdateCustomerInput!
  ): Customer!
  """
  Requires permission `payments:collection:update`.
  
  Corrects a customer collection: its amount, method, date, bank account, reference or notes. Only a collection still open to edits can be changed, and its currency cannot be changed once recorded. The collection date must be valid. Requires permission to update collections.
  """
  updateCustomerCollection(
    """The ID of the customer collection."""
    id: ID!
    """The fields to change."""
    input: UpdateCustomerCollectionInput!
  ): Payment!
  """
  Requires at least one of the permissions `settings:customer_tiers:update` or `settings:tenant:update`.
  
  Saves the customer tier ladder and whether automatic tiering is on. At least one tier is required, and every tier needs a unique name and a distinct, non-negative threshold. Requires permission to update customer tier or tenant settings.
  """
  updateCustomerTierConfig(
    """Whether automatic tiering is on, and the list of tiers."""
    input: UpdateCustomerTierConfigInput!
  ): CustomerTierConfig!
  """
  Requires permission `customers:customer_user:update`.
  
  Changes a customer user's name, role, order limit, approver setting or assigned addresses. The Owner role is always an approver with access to every address. Needs customers:customer_user:update.
  """
  updateCustomerUser(
    """The user and the fields to change."""
    input: UpdateCustomerUserInput!
  ): PartnerCustomerUserDetail!
  """
  Requires permission `purchase:debit_note:update`.
  
  Changes a debit note. Only a PENDING note can be edited. A note raised from a return can change its amounts only to the return's own figures. Needs the debit notes feature on your plan.
  """
  updateDebitNote(
    """The ID of the debit note."""
    id: ID!
    """The fields of the debit note to change."""
    input: UpdateDebitNoteInput!
  ): DebitNoteResponse!
  """
  Requires permission `settings:sales:update`.
  
  Saves how delivery options are shown to customers. Omitted fields keep their saved value, and choosing full tracking also shows the courier name. It takes effect at the next options request. Needs the delivery partners plan feature and permission to update sales settings.
  """
  updateDeliveryCustomerDisplay(
    """The display settings to change."""
    input: UpdateDeliveryCustomerDisplayInput!
  ): DeliveryCustomerDisplay!
  """
  Requires permission `settings:sales:update`.
  
  Saves the box packing settings, in centimetres and kilograms. They take effect at the next delivery quote. Needs the delivery partners plan feature and permission to update sales settings.
  """
  updateDeliveryPackingSettings(
    """
    The units, boxes, fill percentages, volumetric divisor, default item and limits.
    """
    input: UpdateDeliveryPackingSettingsInput!
  ): DeliveryPackingSettings!
  """
  Requires permission `settings:sales:update`.
  
  Changes the organization's delivery settings and returns them. Needs the delivery partners plan feature and permission to update sales settings.
  """
  updateDeliverySettings(
    """The delivery settings to change."""
    input: UpdateDeliverySettingsInput!
  ): DeliverySettingsGql!
  """
  Requires permission `products:discount:update`.
  
  Updates a discount scheme. The discount type is derived from the first discount rule and cannot be set directly. Needs the discounts update permission.
  """
  updateDiscountScheme(
    """The fields to change."""
    data: UpdateDiscountSchemeDto!
    """The ID of the discount scheme."""
    id: String!
  ): DiscountScheme!
  """
  Requires permission `settings:documents:update`.
  
  Create or update the tenant's wording override for one document email type (subject + body, {{token}} placeholders allowed). Empty string clears a field back to the registry default. Admin only.
  """
  updateDocumentEmailCopy(
    """The fields of the document email copy to change."""
    input: UpdateDocumentEmailCopyInput!
  ): DocumentEmailCopy!
  """
  Requires at least one of the permissions `settings:documents:update` or `settings:tenant:update`.
  
  Changes one document number series: its prefix, separator, padding, date format, reset policy or next number. The change waits for any number being issued, so no document is numbered halfway through, and it is audited. Requires permission to update document settings or tenant settings.
  """
  updateDocumentNumberSeries(
    """The document type and the series fields to change."""
    input: UpdateDocumentNumberSeriesInput!
  ): DocumentNumberSeries!
  """
  Requires at least one of the permissions `settings:documents:update` or `settings:tenant:update`.
  
  Updates the document settings: date and number formats, default paper size, watermark, company logo and its position, footer text, digital signature, and archiving. Returns the saved settings. Needs settings:documents:update, or settings:tenant:update.
  """
  updateDocumentSettings(
    """The document settings to change; fields left out stay as they are."""
    input: DocumentSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `settings:documents:update`.
  
  Create or update the tenant document template config (style + branding + footer/terms + column visibility). Admin only.
  """
  updateDocumentTemplateConfig(
    """The fields of the document template config to change."""
    input: UpdateDocumentTemplateConfigInput!
  ): DocumentTemplateConfig!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Changes the organization's email configuration. Whenever the provider, host or port changes, the new connection settings are checked again. Requires permission to update email settings.
  """
  updateEmailConfig(
    """The fields to change."""
    input: UpdateEmailConfigInput!
  ): EmailConfig!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Updates the email settings: SMTP host, port, user, password and encryption, the sender name and address, reply-to, and default CC and BCC for document emails. Returns the saved settings. Needs settings:email:update, or settings:tenant:update.
  """
  updateEmailSettings(
    """The email settings to change; fields left out stay as they are."""
    input: EmailSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `purchase:grn:update`.
  
  Changes a goods receipt. A GRN that has reached a final status cannot have its status changed again, one already posted cannot be linked to a different purchase order, and once it has posted stock its lines cannot be changed: correct it with an inventory adjustment or a purchase return. Lines already billed on a purchase invoice cannot be edited, and the currency must still match the purchase order. Needs the goods receipt (GRN) feature on your plan.
  """
  updateGRN(
    """The goods receipt note fields to change."""
    updateGRNInput: UpdateGRNInput!
  ): GRN!
  """
  Requires permission `settings:integration:update`.
  
  Updates an integration's configuration. Secrets are write-only: one left out or sent blank keeps its stored value, and the configuration is validated after the merge. Requires permission to update integrations.
  """
  updateIntegrationSetting(
    """The ID of the integration and the fields to change."""
    input: UpdateIntegrationSettingInput!
  ): IntegrationSetting!
  """
  Requires at least one of the permissions `settings:inventory:update` or `settings:tenant:update`.
  
  Updates the inventory settings: whether negative stock is allowed, the costing method (AVERAGE unless you chose otherwise), the default unit of measure and warehouse, the low-stock threshold and automatic reorder point, and the batch, serial and expiry tracking switches. Needs the inventory settings update permission, or the tenant settings update permission.
  """
  updateInventorySettings(
    """The details of the inventory settings request."""
    input: InventorySettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `inventory:stock_level:update`.
  
  Sets the alert thresholds on one stock line: reorder point, minimum and maximum quantity, reorder quantity and lead time. They change when you are warned, not what is on the shelf. Setting the reorder point by hand pins it, so the automatic reorder engine never overwrites it. Needs the stock level update permission.
  """
  updateInventoryThresholds(
    """The fields of the inventory thresholds to change."""
    input: UpdateInventoryThresholdsInput!
  ): Inventory!
  """
  Requires at least one of the permissions `payments:invoice:update` or `purchase:purchase_invoice:update`.
  
  Changes an invoice. A fully paid invoice cannot be updated, and an invoice is cancelled with `cancelInvoice`, not through this mutation. A sales invoice keeps the currency it was raised in, and a purchase invoice cannot change currency once payments are allocated to it. The exchange rate must be greater than 0. Changing the payment term recalculates the due date unless you send one. The server recalculates the totals. A sales invoice needs the invoices update permission and a purchase invoice the purchase invoices update permission; moving an invoice to APPROVED also needs the sales invoice approve or purchase invoice approve permission.
  """
  updateInvoice(
    """The ID of the invoice."""
    id: ID!
    """The invoice changes."""
    input: UpdateInvoiceInput!
  ): Invoice!
  """
  Requires permission `platform:language:manage`.
  
  Edits a language record. Languages are shared by every organization, so this needs the platform permission to manage languages, which only platform administrators hold.
  """
  updateLanguage(
    """The fields to change."""
    data: UpdateLanguageInput!
    """The ID of the language."""
    id: String!
  ): Language!
  """
  Requires permission `settings:appearance:update`.
  
  Updates a menu. A parent, when given, must exist in the organization. Needs the appearance settings update permission.
  """
  updateMenu(
    """The ID of the menu and the fields to change."""
    input: UpdateMenuInput!
  ): Menu!
  """
  Requires a customer (portal or buyer app) session.
  
  Buyer 'edit items' (ruling A, 2026-09-11): change quantities / remove lines on the buyer's own order while it is DRAFT, AWAITING_PAYMENT or CONFIRMED, unpaid and uninvoiced, and carries no negotiated (quote / rep) line price. Sends NO prices — every line is re-priced by the pricing authority, re-taxed and re-allocated through the canonical updateSalesOrder path. View-only roles are refused. Returns the refreshed order with fresh amendment flags.
  """
  updateMobileOrderItems(
    """The fields of the mobile order items to change."""
    input: UpdateMobileOrderItemsInput!
  ): MobileOrder!
  """
  Requires a customer (portal or buyer app) session.
  
  Update the buyer's own profile (name, email, company name, business type). Changing the email requires a prior verifyEmailChangeOtp for that address.
  """
  updateMyProfile(
    """The fields of the my profile to change."""
    input: UpdateMyProfileInput!
  ): MobileBuyerProfile!
  """
  Requires at least one of the permissions `settings:notifications:update` or `settings:tenant:update`.
  
  Updates the notification settings: email, push and webhook notifications, the webhook URL, email templates, notification rules and push event rules. Returns the saved settings. Needs settings:notifications:update, or settings:tenant:update.
  """
  updateNotificationSettings(
    """The notification settings to change; fields left out stay as they are."""
    input: NotificationSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `settings:organization:update`.
  
  Changes an organization's details. You can change your own organization; needs settings:organization:update. The change is audited.
  """
  updateOrganization(
    """The ID of the organization."""
    id: String!
    """The organization details to change."""
    input: UpdateOrganizationInput!
  ): Organization!
  """
  Requires at least one of the permissions `customers:customer:update` or `suppliers:supplier:update`.
  
  Updates a partner. The permission needed covers every role the partner will carry after the update, so an update cannot be used to take on the other family's record.
  """
  updatePartner(
    """The ID of the partner and the fields to change."""
    updatePartnerInput: UpdatePartnerInput!
  ): Partner!
  """
  Requires at least one of the permissions `payments:payment:update` or `purchase:payment:update`.
  
  Changes a recorded payment. The status follows how much is allocated: nothing allocated is PENDING, part allocated is PARTIAL and fully allocated is PAID. Refused when the payment does not exist in your organization.
  """
  updatePayment(
    """The ID of the payment."""
    id: ID!
    """The payment changes."""
    input: UpdatePaymentInput!
  ): Payment!
  """
  Requires at least one of the permissions `settings:sales:update` or `settings:tenant:update`.
  
  Changes a payment term. An inactive term cannot be the default. The change is recorded field by field in the audit trail.
  """
  updatePaymentTerm(
    """The payment term changes."""
    input: UpdatePaymentTermInput!
  ): PaymentTerm!
  """
  Requires at least one of the permissions `settings:tenant:update` or `storefront:storefront:update`.
  
  Changes your organization's customer portal and buyer app settings. Only the fields given change. The change is audited. Needs storefront:storefront:update, or settings:tenant:update.
  """
  updatePortalConfig(
    """The settings to change."""
    input: UpdatePortalConfigInput!
  ): PortalConfigResponse!
  """
  Requires permission `products:product:update`.
  
  Updates a product. Requires permission to update products.
  """
  updateProduct(
    """The ID of the product and the fields to change."""
    input: UpdateProductInput!
  ): Product!
  """
  Requires permission `products:product:update`.
  
  Changes a product's delivery flags and merges them into its metadata. A flag left out keeps its value, null clears it, and other metadata is kept. The change is audited. Needs the delivery partners plan feature and permission to update products.
  """
  updateProductDeliveryFlags(
    """The flags to change: own packaging and fragile."""
    input: ProductDeliveryFlagsInput!
    """The ID of the product."""
    productId: ID!
  ): ProductDeliveryFlags!
  """
  Requires permission `products:pricing:update`.
  
  Set the list price of one unit (pack) of a product. It applies to every row of that unit on the product, including variant-level rows. Needs the pricing update permission.
  """
  updateProductUOMListPrice(
    """The new list price of one of this unit."""
    listPrice: Float!
    """The ID of the product."""
    productId: String!
    """The ID of the unit of measure."""
    uomId: String!
  ): BooleanResponse!
  """
  Requires permission `products:pricing:update`.
  
  Set the sale price of one unit (pack) of a product. It applies to every row of that unit on the product, including variant-level rows. Needs the pricing update permission.
  """
  updateProductUOMSalePrice(
    """The ID of the product."""
    productId: String!
    """The new sale price of one of this unit."""
    salePrice: Float!
    """The ID of the unit of measure."""
    uomId: String!
  ): BooleanResponse!
  """
  Requires permission `products:product:update`.
  
  Updates a variant. Changing the SKU to one already in use is refused. Changing opening stock, opening stock cost or cost needs the permission to adjust stock. Requires permission to update products.
  """
  updateProductVariant(
    """The ID of the variant."""
    id: ID!
    """The fields to change on the variant."""
    updateProductVariantInput: UpdateProductVariantInput!
  ): ProductVariant!
  """
  Requires an authenticated session.
  
  Updates the signed-in user's own profile: name, email, phone, avatar, bio, address and city.
  """
  updateProfile(
    """The profile fields to change."""
    input: UpdateProfileInput!
  ): User!
  """
  Requires at least one of the permissions `settings:purchase:update` or `settings:tenant:update`.
  
  Updates the purchase settings: the default supplier, purchaser, payment terms and receiving warehouse, whether goods receipts and purchase returns are enabled, and the approval requirements for purchases. Needs the purchase settings update permission, or the tenant settings update permission.
  """
  updatePurchaseSettings(
    """The details of the purchase settings request."""
    input: PurchaseSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `sales:quote:update`.
  
  Update a quote's header, lines or terms. Converted quotes cannot be edited. Send the quote id inside the input.
  """
  updateQuote(
    """The quote changes. The quote id is part of the input."""
    input: UpdateQuoteInput!
  ): Quote!
  """
  Requires permission `platform:region:manage`.
  
  Edits a region. Regions are shared by every organization, so this needs the platform permission to manage regions, which only platform administrators hold.
  """
  updateRegion(
    """The ID of the region."""
    id: String!
    """The fields to change."""
    input: UpdateRegionInput!
  ): Region!
  """
  Requires permission `sales:credit_note:update`.
  
  Records the customer's satisfaction rating and feedback on a return. A rating of 3 or more counts as satisfied. Needs the credit notes update permission.
  """
  updateReturnSatisfaction(
    """The customer's written feedback."""
    feedback: String!
    """The customer rating, as a whole number."""
    rating: Int!
    """The ID of the return."""
    returnId: String!
  ): ReturnResponse!
  """
  Requires at least one of the permissions `purchase:debit_note:update` or `sales:credit_note:update`.
  
  Sets the courier service and tracking number on a return and moves it to IN_TRANSIT. Needs the update permission of the return's direction.
  """
  updateReturnTracking(
    """The name of the courier."""
    courierService: String!
    """The ID of the return."""
    returnId: String!
    """The courier tracking number."""
    trackingNumber: String!
  ): ReturnResponse!
  """
  Requires permission `settings:role:update`.
  
  Updates a role. Refused if the new name belongs to a soft-deleted role. Needs settings:role:update.
  """
  updateRole(
    """The ID of the role and the fields to change."""
    input: UpdateRoleInput!
  ): Role!
  """
  Requires permission `settings:permission:update`.
  
  Replaces the full set of permissions on a role with the given list. Every permission being added must be one you hold yourself, and platform-reserved permissions are refused. Returns true on success. Needs settings:permission:update.
  """
  updateRolePermissions(
    """The IDs of the permissions the role should have after the update."""
    permissionIds: [ID!]!
    """The ID of the role."""
    roleId: ID!
  ): Boolean!
  """
  Requires permission `products:product:update`.
  
  Updates a SKU pattern. Any brand or category it is changed to must belong to the organization. Needs the products update permission.
  """
  updateSKUPattern(
    """The ID of the SKU pattern."""
    id: ID!
    """The fields to change."""
    updateSKUPatternInput: UpdateSKUPatternInput!
  ): SKUPattern!
  """
  Requires permission `sales:sales_order:update`.
  
  Update an order. Header fields stay editable until the order is cancelled or returned. Lines, shipping and discount can be amended while the order is unpaid and not yet shipped or invoiced. Currency, rate and tax method are fixed once the order leaves DRAFT.
  """
  updateSalesOrder(
    """The ID of the sales order."""
    id: ID!
    """The order changes."""
    input: UpdateSalesOrderInput!
  ): SalesOrder!
  """
  Requires permission `sales:sales_order:update`.
  
  Move an order to another status. Only transitions the status matrix allows are accepted. Moving to CONFIRMED, CANCELLED or DELIVERED also needs the confirm, cancel or deliver permission. Send expectedVersion to guard against concurrent edits.
  """
  updateSalesOrderStatus(
    """
    The version of the record you last read. The change is refused if someone else changed it since.
    """
    expectedVersion: Int
    """The ID of the sales order."""
    id: ID!
    """The status to move the order to."""
    status: SalesOrderStatus!
  ): SalesOrder!
  """
  Requires at least one of the permissions `settings:sales:update` or `settings:tenant:update`.
  
  Sets the highest discount percentage a manual price override may imply; 100 means no ceiling. Needs settings:sales:update, or settings:tenant:update.
  """
  updateSalesPolicy(
    """The new discount ceiling."""
    input: UpdateSalesPolicyInput!
  ): SalesPolicy!
  """
  Requires at least one of the permissions `settings:sales:update` or `settings:tenant:update`.
  
  Updates the sales settings: default salesperson, payment terms and tax rate, discounts and their ceiling, approval for large orders and its threshold, quotations, and whether shipping needs an invoice first. Returns the saved settings. Needs settings:sales:update, or settings:tenant:update.
  """
  updateSalesSettings(
    """The sales settings to change; fields left out stay as they are."""
    input: SalesSettingsInput!
  ): [TenantSetting!]!
  """
  Requires at least one of the permissions `settings:security:update` or `settings:tenant:update`.
  
  Updates the security settings: two-factor sign-in, forced password change, password policy, session timeout, single sign-on, allowed domains, audit log, IP allow list and encrypted exports. Returns the saved settings. Needs settings:security:update, or settings:tenant:update.
  """
  updateSecuritySettings(
    """The security settings to change; fields left out stay as they are."""
    input: SecuritySettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `settings:integration:update`.
  
  Changes the organization's marketing send rules. Omitted fields keep their current value, and the send window must close after it opens. Requires permission to update integrations.
  """
  updateSendGovernorSettings(
    """
    The fields to change: marketing on or off, weekly and daily caps, and the send window hours.
    """
    input: UpdateSendGovernorSettingsInput!
  ): SendGovernorSettingsGql!
  """
  Requires permission `marketing:link:write`.
  
  Changes a short link's title, description or active state. A link that is inactive or expired stops redirecting. Needs the marketing link write permission.
  """
  updateShortUrl(
    """The new description. Omit it to leave the description unchanged."""
    description: String
    """The ID of the short link."""
    id: String!
    """
    False to stop the link redirecting, true to turn it back on. Omit it to leave it unchanged.
    """
    isActive: Boolean
    """The new title. Omit it to leave the title unchanged."""
    title: String
  ): ShortUrlEntity!
  """
  Requires at least one of the permissions `settings:system:update` or `settings:tenant:update`.
  
  Updates the system settings: system name and version, maintenance mode and its message, debug mode, log level, analytics and default theme. Returns the saved settings. Needs settings:system:update, or settings:tenant:update.
  """
  updateSystemSettings(
    """The system settings to change; fields left out stay as they are."""
    input: SystemSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `products:tax:update`.
  
  Updates a tax group, including which rates it holds. A code already used by another group is refused. A group that the catalog or the organization's defaults rely on cannot be deactivated or emptied of its active rates. Needs the tax update permission.
  """
  updateTaxGroup(
    """The ID of the tax group and the fields to change."""
    input: UpdateTaxGroupInput!
  ): TaxGroup!
  """
  Requires permission `products:tax:update`.
  
  Updates a tax rate. A code already used by another rate is refused. A rate cannot be deactivated while the catalog or the organization's defaults rely on it, or when it is the only live rate of a group in use. Needs the tax update permission.
  """
  updateTaxRate(
    """The ID of the tax rate and the fields to change."""
    input: UpdateTaxRateInput!
  ): TaxRate!
  """
  Requires permission `settings:tenant:update`.
  
  Update the organization's fiscal year start month (reporting calendar only)
  """
  updateTenantLocalization(
    """The fields of the tenant localization to change."""
    input: UpdateTenantLocalizationInput!
  ): OrganizationExtensionInfo!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Changes the quote reply address, the sender name suffix and whether quotes may be emailed. Omitted fields keep their value, and the change is audited. Requires permission to update email or tenant settings.
  """
  updateTenantReplyEmailSettings(
    """The reply address, sender name suffix and sending switch to change."""
    input: UpdateTenantReplyEmailInput!
  ): TenantEmailSettings!
  """
  Requires permission `settings:tenant:update`.
  
  Changes one setting by ID. A category that has its own update operation is refused. Needs settings:tenant:update.
  """
  updateTenantSetting(
    """The setting's ID and the fields to change."""
    input: UpdateTenantSettingInput!
  ): TenantSetting!
  """
  Requires at least one of the permissions `settings:regional:update` or `settings:tenant:update`.
  
  Changes a timezone's name, offset, daylight-saving rules or sort order. A code already used by another timezone is refused. Setting it as default takes over from the current default. Requires permission to update regional or tenant settings.
  """
  updateTimezone(
    """The ID of the timezone."""
    id: String!
    """The fields to change."""
    updateTimezoneInput: UpdateTimezoneInput!
  ): Timezone!
  """
  Requires permission `products:product:update`.
  
  Change a unit of measure. Only the fields you send change, and the code and category cannot be changed. A COUNT unit keeps its whole-number rules. A unit that is the organization's default unit, or the base unit of a product, cannot be deactivated. Needs the products update permission.
  """
  updateUOM(
    """The unit changes."""
    data: UpdateUOMInput!
    """The ID of the unit of measure."""
    id: String!
  ): UnitOfMeasure!
  """
  Requires permission `users:user:update`.
  
  Updates a user. A user in another organization is refused unless you hold the cross-organization user update permission. Needs users:user:update.
  """
  updateUser(
    """The ID of the user."""
    id: String!
    """The fields to change."""
    input: UpdateUserInput!
  ): User!
  """
  Requires an authenticated session.
  
  Saves the signed-in user's own preferences: language, currency, region, time zone and date, time and number formats. Available to customer apps too.
  """
  updateUserPreferences(
    """The preferences to save."""
    input: UpdateUserPreferencesInput!
  ): UserPreference!
  """
  Requires permission `users:user:update`.
  
  Updates a reporting relationship in your organization. Needs users:user:update.
  """
  updateUserRelationship(
    """The ID of the user relationship."""
    id: String!
    """The fields to change."""
    input: UpdateUserRelationshipInput!
  ): UserRelationship!
  """
  Requires at least one of the permissions `settings:tenant:update` or `settings:user:update`.
  
  Updates the user settings: default language, timezone, date and time format and currency, multiple logins, profile image size and notifications. Returns the saved settings. Needs settings:user:update, or settings:tenant:update.
  """
  updateUserSettings(
    """The user settings to change; fields left out stay as they are."""
    input: UserSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `suppliers:supplier:update`.
  
  Updates a supplier-to-variant mapping. Re-pointing it to another supplier, product or variant is checked against the organization. Needs the suppliers update permission.
  """
  updateVendorProduct(
    """The ID of the mapping and the fields to change."""
    updateVendorProductInput: UpdateVendorProductInput!
  ): VendorProduct!
  """
  Requires permission `inventory:warehouse:update`.
  
  Updates a warehouse, including its code and status. A code already used by another warehouse is refused. Needs the warehouse update permission.
  """
  updateWarehouse(
    """The ID of the warehouse."""
    id: ID!
    """The fields to change."""
    input: UpdateWarehouseInput!
  ): Warehouse!
  """
  Requires permission `settings:webhooks:update`.
  
  Updates a webhook endpoint's name, receiver URL, subscribed events or active state. The same URL and event rules as creation apply, and the signing secret is not changed. Requires permission to update webhooks.
  """
  updateWebhookEndpoint(
    """The ID of the webhook endpoint."""
    id: ID!
    """
    The endpoint's name, receiver URL, subscribed event types and whether it is active.
    """
    input: WebhookEndpointInput!
  ): WebhookEndpoint!
  """
  Requires at least one of the permissions `settings:tenant:update` or `settings:webhooks:update`.
  
  Updates the webhook settings: whether webhooks are on, retries and their delay, timeout, signing, logging and log retention, rate limiting, and batching. Returns the saved settings. Needs settings:webhooks:update, or settings:tenant:update.
  """
  updateWebhookSettings(
    """The webhook settings to change; fields left out stay as they are."""
    input: WebhookSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `settings:integration:update`.
  
  Switches one WhatsApp trigger on or off and maps it to a message template. The template must exist in the provider account, and a template must be chosen before a trigger can be enabled. Requires permission to update integrations.
  """
  updateWhatsAppTrigger(
    """The trigger, the template name and whether the trigger is enabled."""
    input: UpdateWhatsAppTriggerInput!
    """
    The WhatsApp provider to use. Omit it to use the organization's enabled provider, else its most recently edited one.
    """
    provider: WhatsAppProvider
  ): WhatsAppConfigGql!
  """
  Requires at least one of the permissions `settings:tenant:update` or `settings:workflows:update`.
  
  Updates the workflow settings: whether workflows are on, the auto-approve threshold, required comments, approval and rejection notices, escalation and its timeout, parallel approvals, delegation and history. Returns the saved settings. Needs settings:workflows:update, or settings:tenant:update.
  """
  updateWorkflowSettings(
    """The workflow settings to change; fields left out stay as they are."""
    input: WorkflowSettingsInput!
  ): [TenantSetting!]!
  """
  Requires permission `products:product:update`.
  
  Get a pre-signed URL for uploading a unit's icon image. Allowed types are JPEG, PNG, GIF and WEBP. Needs the products update permission.
  """
  uploadUOMImage(
    """The unit and the file to upload."""
    data: UploadUOMImageInput!
  ): UploadUOMImageResult!
  """
  Requires permission `settings:integration:update`.
  
  Creates or updates a delivery partner configuration. Secret fields are write-only and stored encrypted, and an empty value keeps the stored one. Changing credentials takes an enabled partner offline until it is verified again. A rate-card courier prices in the organization's base currency, and a manual courier is verified on save. Setting up a provider that is already set up is refused. Needs the delivery partners plan feature and permission to update integrations.
  """
  upsertDeliveryPartnerConfig(
    """The provider, display name, credentials and provider settings."""
    input: UpsertDeliveryPartnerConfigInput!
  ): DeliveryPartnerConfigGql!
  """
  Requires permission `visits:journey-plan:manage`.
  
  Replaces a sales rep's route for one day. Stops are matched by customer: kept stops are re-ordered, new stops are added as planned visits, and removed stops are deleted. A stop that already has a check-in cannot be removed, and the whole change is refused. The rep must belong to the organization. Requires permission to manage journey plans.
  """
  upsertJourneyPlan(
    """The rep, the day, optional notes and the list of stops."""
    input: UpsertJourneyPlanInput!
  ): JourneyPlan!
  """
  Requires permission `settings:integration:update`.
  
  Creates or updates the credentials and settings for one payment provider. Credentials are stored encrypted, and a credential field the provider does not define is refused. Enabling the gateway is a separate step: `setPaymentGatewayEnabled`.
  """
  upsertPaymentGatewayConfig(
    """The gateway configuration to create or update."""
    input: UpsertPaymentGatewayConfigInput!
  ): PaymentGatewayConfigGql!
  """
  Requires permission `settings:integration:update`.
  
  Creates or updates the WhatsApp configuration for a provider. Entering a new API key clears the verification, so the connection must be tested again. Requires permission to update integrations.
  """
  upsertWhatsAppConfig(
    """The provider, API key and provider settings such as the channel."""
    input: UpsertWhatsAppConfigInput!
  ): WhatsAppConfigGql!
  """
  Requires permission `settings:integration:update`.
  
  Checks every integration's credentials with its service and returns each one's status, valid or invalid, with the error when invalid. Requires permission to update integrations.
  """
  validateAllIntegrations: [IntegrationStatus!]!
  """
  Requires permission `settings:integration:update`.
  
  Checks one integration's credentials with the service and records whether they are valid, with the error when they are not. Requires permission to update integrations.
  """
  validateIntegration(
    """The ID of the integration to validate."""
    input: ValidateIntegrationInput!
  ): IntegrationSetting!
  """
  Public: no authentication required.
  
  Verifies the OTP and logs the customer in. Blocked (ForbiddenException) until the partner is ACTIVE — a pending self-registered customer sees the pending-approval message instead of a session.
  """
  verifyCustomerOtp(
    """The details of the verify customer otp request."""
    input: VerifyCustomerOtpInput!
  ): CustomerAuthResponse!
  """
  Public: no authentication required.
  
  Check a registration OTP without creating an account and without consuming the code, so the registration form can be opened knowing the mailbox is owned and the same code can still sign the new account in afterwards.
  """
  verifyCustomerRegistrationOtp(
    """The details of the verify customer otp request."""
    input: VerifyCustomerOtpInput!
  ): Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  Step 2: verify the code sent to the new address and record proof of ownership server-side. Returns true/false only — no token is handed to the client. `updateMyProfile` consumes that proof when it writes the new email, so the address is not changed until the buyer saves.
  """
  verifyEmailChangeOtp(
    """The details of the verify email change otp request."""
    input: VerifyEmailChangeOtpInput!
  ): Boolean!
  """
  Public: no authentication required.
  
  Verify the 6-digit OTP and return access + refresh tokens.
  """
  verifyEmailOtp(
    """The details of the verify email otp request."""
    input: VerifyEmailOtpInput!
  ): MobileAuthResponse!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Checks the published DNS records of the registered sender domain with the email provider and returns the updated status. Requires permission to update email settings.
  """
  verifyEmailSenderDomain: EmailSenderDomain!
  """
  Public: no authentication required.
  
  Step 2 of registering an organization by email: checks the emailed code and returns a short-lived verification token for registerWithOtp. Rate-limited per IP address. No sign-in needed.
  """
  verifyRegistrationOtp(
    """The request ID, the email address and the code."""
    input: VerifyRegistrationOtpInput!
  ): VerifyRegistrationOtpResponse!
  """
  Public: no authentication required.
  
  Finishes a sign-in that needs a second factor, using the temporary token from the sign-in and a verification code. Returns tokens and a session token.
  """
  verifyTwoFactor(
    """
    The user ID, the verification code and the temporary token from the sign-in.
    """
    input: VerifyTwoFactorInput!
  ): AuthResponse!
  """
  Requires permission `sales:credit_note:update`.
  
  Voids a credit note. Only APPROVED or partially applied notes can be voided. Voiding a note that was applied reverses every reduction it made to invoices, so those invoices owe the money again.
  """
  voidCreditNote(
    """The ID of the credit note."""
    id: ID!
    """Why the credit note is voided."""
    reason: String!
  ): CreditNote!
  """
  Requires at least one of the permissions `payments:payment:void` or `purchase:payment:void`.
  
  Voids a payment. A payment that is DRAFT or PENDING with nothing allocated is simply cancelled and the partner balance it took is restored. A settled payment has its live allocations reversed and the posted balance restored. A payment taken through an online gateway also raises one credit note for the full amount, with no refund call to the provider. Money already given back by cancelling an invoice is not given back twice. A payment already voided, reversed or refunded is returned unchanged.
  """
  voidPayment(
    """The payment to void and the reason."""
    input: VoidPaymentInput!
  ): Payment!
  """
  Requires permission `settings:integration:update`.
  
  Queues an immediate Zoho sync poll for one entity type, instead of waiting for the next scheduled one. Returns a JSON string confirming it was queued. Requires permission to update integrations.
  """
  zohoForcePoll(
    """
    The kind of record to poll for, such as products, customers, sales orders, invoices or payments.
    """
    entityType: String!
  ): String!
  """
  Requires permission `settings:integration:update`.
  
  Queues an immediate Zoho reconciliation run for the organization. Returns a JSON string confirming it was queued. Requires permission to update integrations.
  """
  zohoForceReconciliation: String!
  """
  Requires permission `settings:integration:update`.
  
  Resumes a stopped Zoho data migration from its checkpoint and returns the checkpoint as a JSON string. Requires permission to update integrations.
  """
  zohoResumeMigration: String!
  """
  Requires permission `settings:integration:update`.
  
  Queues a retry of one failed Zoho sync log entry and returns a JSON string with the name of the queued job. Requires permission to update integrations.
  """
  zohoRetryFailedSync(
    """The ID of the failed sync log entry."""
    syncLogId: String!
  ): String!
  """
  Requires permission `settings:integration:update`.
  
  Sets how many Zoho API calls the organization may make per day. Zero or no value clears the cap and goes back to the plan tier's limit. Returns a JSON string with the limit now in force. Requires permission to update integrations.
  """
  zohoSetApiLimit(
    """The daily call cap. Omit it, or send 0, to clear the cap."""
    limit: Int
  ): String!
  """
  Requires permission `settings:integration:update`.
  
  Starts the one-time migration of data from Zoho, optionally limited to some warehouses, and returns its checkpoint as a JSON string. It starts a whole-catalog migration in one call. Requires permission to update integrations.
  """
  zohoStartMigration(
    """Limit the migration to these warehouses. Omit it to migrate all."""
    warehouseIds: [String!]
  ): String!
}

"""
A buyer-owned ordering location, backed by an Address row (type SHIPPING/DELIVERY). `isActive: false` means the address is pending a seller's approval and cannot be ordered against.
"""
type MyAddress {
  """The first line of the address."""
  addressLine1: String
  """Address classification (AddressType enum)."""
  addressType: AddressType!
  """The city."""
  city: String
  """The country."""
  country: String
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """
  TRUE when this address also serves the OTHER role — a SHIPPING address that is billed to as well, or vice versa. `addressType` stays the primary classification (one enum column cannot hold two roles), so this is the flag that distinguishes a shipping-only address from a shipping+billing one. Drives the cart/checkout heading: 'Shipping To' / 'Billing To' / 'Billing & Shipping'. Nullable for app builds that predate it.
  """
  isDualPurpose: Boolean
  """The latitude of the address on the map."""
  lat: Float
  """The longitude of the address on the map."""
  lng: Float
  """The name of the address."""
  name: String!
  "Phone number."
  phone: String!
  """The postal code. Empty when the buyer has none."""
  postalCode: String
  """The state or region."""
  state: String
  """The delivery zone of the address."""
  zone: String
}

"""
The buyer's current customer-tier status for the active outlet: effective tier, its discount %, this month's spend, and progress to the next tier. Drives the loyalty TierCard. Tier resolution matches the price the buyer is actually charged.
"""
type MyCustomerTier {
  """Whether auto-tiering is enabled for this organization."""
  autoTieringEnabled: Boolean!
  """
  Whether this customer is manually pinned to a tier (auto-tiering skips them).
  """
  locked: Boolean!
  """Current calendar-month order total (drives auto-tiering)."""
  monthlySpend: Float!
  """Discount % the next tier unlocks (e.g. 15 for Diamond)."""
  nextTierDiscountPercentage: Float
  """Name of the next tier up, if any."""
  nextTierName: String
  """Monthly-spend threshold of the next tier."""
  nextTierThreshold: Float
  """Spend remaining to reach the next tier."""
  remainingToNextTier: Float
  """Discount % applied by this tier (0 when the tier has no scheme)."""
  tierDiscountPercentage: Float!
  """Effective tier key (e.g. GOLD)."""
  tierKey: String!
  """Display name of the effective tier (e.g. Gold)."""
  tierName: String!
  """
  This tier's OWN spend floor — the lower bound of a current-tier-to-next-tier progress bar.
  """
  tierThreshold: Float!
}

"""An organization the signed-in user belongs to."""
type MyOrganization {
  """The organization code."""
  code: String
  "The unique ID of this record."
  id: String!
  """The organization's default language."""
  language: String
  """The URL of the organization logo."""
  logoUrl: String
  """The name of the organization."""
  name: String!
  """Which features the plan includes."""
  planFeatures: JSON
  """The limits the plan sets."""
  planLimits: JSON
  """The name of the organization's plan."""
  planName: String
  """The user's role in the organization."""
  role: String!
  """The subdomain of the organization."""
  subdomain: String!
}

"""Notification settings."""
input NotificationSettingsInput {
  """True to send email notifications."""
  emailNotifications: Boolean
  """The email templates in use."""
  emailTemplates: [String!]
  """The notification rules, as JSON."""
  notificationRules: JSON
  """
  Per-kind push opt-outs, for example buyer order_shipped set to false. A missing kind is on.
  """
  pushEventRules: JSON
  """True to send push notifications."""
  pushNotifications: Boolean
  """True to send webhook notifications."""
  webhookNotifications: Boolean
  """The webhook address."""
  webhookUrl: String
}

"""
What returns already hold against one order line, and what a new return made against the order may still take.
"""
type OrderLineReturns {
  """The order line's id."""
  orderItemId: ID!
  """
  Units a new return against the order may still take for this line, never below zero: the ordered quantity (sales order) or received quantity (purchase order), less returnedQuantity. Creating a return refuses more.
  """
  returnableQuantity: Float!
  """
  Units on returns made against this order line that are not cancelled or rejected, in the line's unit of measure.
  """
  returnedQuantity: Float!
}

"""One variant to price in a batch, for the sales app order pad."""
input OrderPadVariantPriceRequestInput {
  """The quantity to price."""
  quantity: Float
  "The ID of the unit of measure."
  uomId: String
  "The ID of the product variant."
  variantId: String!
}

"""
The order's own shipping charge, so the ship dialog can show what a courier rate would do to it.
"""
type OrderShippingCharge {
  """The order's current shipping charge, in its currency."""
  amount: Float!
  "ISO 4217 currency code."
  currency: String!
  """
  Empty when a courier rate may replace the shipping charge. Otherwise the exact reason it cannot.
  """
  lockReason: String
}

"""Orders in one status."""
type OrderStatus {
  """How many orders."""
  count: Int!
  """The status."""
  status: String!
  """Their value."""
  value: Float!
}

"""A seller organization: one tenant of the platform."""
type Organization {
  """The street address."""
  address: String
  """The city."""
  city: String
  """The organization code."""
  code: String!
  """The country."""
  country: String
  "When the record was created."
  createdAt: DateTime!
  """
  True when credit limits are enforced. When false, enforcement is skipped for sales and purchase order confirmation.
  """
  creditLimitEnabled: Boolean!
  "ISO 4217 currency code."
  currency: String!
  """The date format."""
  dateFormat: String!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "Email address."
  email: String!
  "The unique ID of this record."
  id: String!
  """The organization's industry."""
  industry: String
  """The default language."""
  language: String!
  """The latitude of the company address on the map."""
  latitude: Float
  """The URL of the organization logo."""
  logo: String
  """The longitude of the company address on the map."""
  longitude: Float
  """The name of the organization."""
  name: String!
  "Phone number."
  phone: String
  """The postal code."""
  postalCode: String
  """The organization's company registration number."""
  registrationNumber: String
  """The organization's settings, as JSON."""
  settings: JSON
  """The size of the organization."""
  size: String
  """The state or region."""
  state: String
  """
  Headline figures about the organization. Empty without the permission to see them.
  """
  stats: OrganizationStats
  """The status of the organization."""
  status: String!
  """The subdomain the organization is reached on."""
  subdomain: String!
  """When the subscription ends."""
  subscriptionExpiresAt: DateTime
  """The name of the subscription plan."""
  subscriptionPlan: String
  """The status of the subscription."""
  subscriptionStatus: String
  """The organization's tax ID."""
  taxId: String
  """The time zone of the organization."""
  timezone: String!
  "When the record was last changed."
  updatedAt: DateTime!
  """The organization's website."""
  website: String
}

"""A host name the organization's portal answers on."""
type OrganizationDomain {
  "When the record was created."
  createdAt: DateTime!
  """The host name."""
  hostname: String!
  "The unique ID of this record."
  id: ID!
  """True when this is the main address of the portal."""
  isPrimary: Boolean!
  """Whether it is the platform subdomain or a custom domain."""
  kind: PortalDomainKind!
  """Where the domain stands."""
  status: PortalDomainStatus!
  """
  Human-readable detail for the current status (e.g. why a domain FAILED).
  """
  statusMessage: String
  """
  DNS validation record the customer must publish (CNAME/TXT) for a CUSTOM domain — populated once the control plane responds.
  """
  validationRecord: JSON
  """When the domain was verified."""
  verifiedAt: DateTime
}

"""The organization's localization settings."""
type OrganizationExtensionInfo {
  """The ID of the base currency."""
  baseCurrencyId: String
  """The country code."""
  countryCode: String
  """The date format."""
  dateFormat: String
  """When the fiscal year starts, as MM-DD."""
  fiscalYearStart: String
  """The month the fiscal year starts, for a select."""
  fiscalYearStartMonth: Int
  "The unique ID of this record."
  id: String!
  """The character between the whole and decimal parts of a number."""
  numberDecimalSeparator: String
  """The character between thousands."""
  numberThousandSeparator: String
  """The main time zone."""
  primaryTimezone: String
  """The tax system in use."""
  taxSystem: String
  """The time format."""
  timeFormat: String
}

"""Headline figures about an organization."""
type OrganizationStats {
  """How many warehouses are active."""
  activeWarehhouses: Int!
  """The date of the last order."""
  lastOrderDate: DateTime
  """How many orders there are."""
  totalOrders: Int!
  """How many products there are."""
  totalProducts: Int!
  """The total revenue."""
  totalRevenue: Float!
  """How many users there are."""
  totalUsers: Int!
}

"""The organization's tax configuration."""
type OrganizationTaxConfiguration {
  "When the record was created."
  createdAt: DateTime!
  """The ID of the tax group used for purchases when a product has none."""
  defaultPurchaseTaxGroupId: String
  """
  The ID of the tax group used for sales when a product has none. Null means a product must carry its own tax.
  """
  defaultSalesTaxGroupId: String
  """
  Whether prices include tax, exclude it, or compound it, when nothing else says.
  """
  defaultTaxCalculation: TaxCalculationMethod!
  """True to switch on e-way bill support."""
  enableEWayBill: Boolean!
  """True to switch on GST compliance features."""
  enableGSTCompliance: Boolean!
  """True to allow tax rules for more than one country."""
  enableMultiCountryTax: Boolean!
  """True to let each product carry its own tax setup."""
  enableProductTaxMapping: Boolean!
  """True to switch on tax alerts."""
  enableTaxAlerts: Boolean!
  """True to keep an audit log of tax changes."""
  enableTaxAuditLog: Boolean!
  """True to allow tax exemptions."""
  enableTaxExemption: Boolean!
  """True to allow tax-inclusive pricing."""
  enableTaxInclusive: Boolean!
  """True to switch on tax reporting."""
  enableTaxReporting: Boolean!
  """The organization's GST registration number."""
  gstNumber: String
  """The state the organization is registered in for GST."""
  gstState: String
  """The organization's home currency code."""
  homeCurrency: String!
  "The unique ID of this record."
  id: ID!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """How tax amounts are rounded."""
  taxRoundingMethod: String!
  """How many decimal places tax amounts are rounded to."""
  taxRoundingPrecision: Int!
  """The kind of tax system the organization uses."""
  taxSystemType: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""The document a credit note was raised against."""
type OriginalDocument {
  """The number of the document."""
  number: String!
  """The kind of document, for example invoice."""
  type: String!
}

"""
Step 3 of signing up: creates the organization. It needs the verification token from step 2.
"""
input OtpRegisterInput {
  """The name of the company."""
  companyName: String!
  """The country."""
  country: String!
  "ISO 4217 currency code."
  currency: String
  """The date format."""
  dateFormat: String
  "Email address."
  email: String!
  """The person's first name."""
  firstName: String
  """The language."""
  language: String
  """The person's last name."""
  lastName: String
  """The subdomain for the organization."""
  subdomain: String!
  """The time zone."""
  timezone: String
  """Verification token returned by verifyRegistrationOtp"""
  verificationToken: String!
}

"""
The result of step 3 of signing up. The organization is set up at once, and the onboarding ID lets the portal follow the rest of the setup.
"""
type OtpRegisterResponse {
  """A message about the outcome."""
  message: String
  """Onboarding session ID for SSE progress tracking"""
  onboardingId: String
  """
  The provisioned organization id (control plane persists it in the tenant registry)
  """
  organizationId: String
  """True when the organization was created."""
  success: Boolean!
  """If true, client should subscribe to SSE for progress"""
  useAsyncOnboarding: Boolean
}

"""A page of outbound document emails."""
type OutboxDeliveryPage {
  """The emails on this page."""
  items: [OutboxDeliveryRow!]!
  """How many there are in all."""
  total: Int!
}

"""One outbound document email and where its delivery stands."""
type OutboxDeliveryRow {
  """How many attempts were made."""
  attempts: Int!
  """A fingerprint of the content that was sent."""
  contentHash: String
  "When the record was created."
  createdAt: DateTime!
  """When it was delivered."""
  deliveredAt: DateTime
  """The number of the document."""
  documentNumber: String
  """The kind of document sent."""
  documentType: String!
  "The unique ID of this record."
  id: String!
  """The error from the last attempt."""
  lastError: String
  """How many attempts are allowed."""
  maxAttempts: Int!
  """When the next attempt will be made."""
  nextAttemptAt: DateTime!
  """The address it was sent to."""
  recipient: String!
  """Where the delivery stands."""
  status: OutboxDeliveryStatus!
  """A fingerprint of the template version used."""
  templateVersionHash: String
}

"""Lifecycle status of a durable document-delivery outbox row."""
enum OutboxDeliveryStatus {
  """Sent successfully."""
  DELIVERED
  """Sending failed."""
  FAILED
  """Waiting to be sent."""
  PENDING
  """Being sent now."""
  PROCESSING
}

"""A customer or vendor that has an open balance."""
type OutstandingPartnerRef {
  "The ID of the partner."
  partnerId: String!
  """The name of the customer or vendor."""
  partnerName: String!
}

"""
Outstanding and aging totals over the whole open invoice set, in the organization's base currency. Cancelled, voided and draft invoices are left out.
"""
type OutstandingSummary {
  """
  The outstanding amount in the five aging buckets: current, 1-30, 31-60, 61-90 and 90+ days.
  """
  aging: [AgingBucket!]!
  """
  The average age in days since the invoice date, weighted by the amount outstanding.
  """
  averageDaysOutstanding: Float!
  """The part of the outstanding total that is not yet due."""
  currentAmount: Float!
  """The part of the outstanding total that is past due."""
  overdueAmount: Float!
  """Every customer or vendor with an open balance, sorted by name."""
  partners: [OutstandingPartnerRef!]!
  """How many distinct customers or vendors have open invoices."""
  totalCustomers: Int!
  """How many open invoices are in scope."""
  totalInvoices: Int!
  """The total still owed on open invoices, in the base currency."""
  totalOutstanding: Float!
}

"""The overall result of a return inspection."""
enum OverallResult {
  """The inspection failed."""
  FAIL
  """Part of the shipment passed."""
  PARTIAL
  """The inspection passed."""
  PASS
}

"""One box (or own-packaging item) of a packing, cm / kg."""
type PackedBox {
  """
  The box id; null for an own-packaging / oversize item or the default parcel.
  """
  boxId: String
  """The greater of the two."""
  chargeableWeightKg: Float!
  """Holds fragile items only (packed apart, at the fragile fill)."""
  fragile: Boolean!
  """The height, in centimetres."""
  heightCm: Float!
  """What is in the box."""
  items: [PackedBoxItem!]!
  """
  Staff screens: a suggested arrangement of the contents, for the first box of each distinct contents of a plan; null for a repeat (see layoutSameAsIndex), past the drawing limit, and where it is not worked out.
  """
  layout: PackedBoxLayout
  """
  For a box with the same contents as an earlier box of the plan: that box's 0-based index, whose layout this one shares. Null otherwise.
  """
  layoutSameAsIndex: Int
  """
  As a courier measures it: the box's outside length when set, else its inside.
  """
  lengthCm: Float!
  """The name of the box."""
  name: String!
  """L×W×H ÷ the settings' divisor."""
  volumetricWeightKg: Float!
  """Contents + the box itself."""
  weightKg: Float!
  """The width, in centimetres."""
  widthCm: Float!
}

"""One item inside a packed box."""
type PackedBoxItem {
  """Base units."""
  quantity: Float!
  "The ID of the product variant."
  variantId: ID!
}

"""
A suggested arrangement of one box's contents by shape, for staff screens. It never changes the packing: which box and what goes in it stay the packing engine's, which counts volume, weight and fit in some rotation only — so units that find no place by shape are listed as unplaced.
"""
type PackedBoxLayout {
  """
  How full the box may be packed by volume, in percent (the fragile fill when the box is fragile).
  """
  fillPercent: Float!
  """The box's inside height, in centimetres."""
  insideHeightCm: Float!
  """The box's inside length, in centimetres."""
  insideLengthCm: Float!
  """The box's inside width, in centimetres."""
  insideWidthCm: Float!
  """
  The box's maximum packed weight in kilograms; null when the box is not a saved box.
  """
  maxWeightKg: Float
  """Units not drawn because the box holds more than the drawing limit."""
  notDrawnCount: Int!
  """Where each drawn unit sits."""
  placements: [PackedBoxPlacement!]!
  """
  The empty box's own weight in kilograms; null when the box is not a saved box.
  """
  tareWeightKg: Float
  """Units counted in this box that find no place by shape."""
  unplaced: [PackedBoxItem!]!
  """Units with no size: counted by weight only, never drawn."""
  unsized: [PackedBoxItem!]!
}

"""
Where one unit sits in a box's suggested arrangement: cm from the box's inside back-left floor corner (x along the length, y along the width, z up), with the unit's sides as placed.
"""
type PackedBoxPlacement {
  """The unit's height, as placed."""
  heightCm: Float!
  """The unit's side along the box length, as placed."""
  lengthCm: Float!
  """The product variant this unit is."""
  variantId: ID!
  """The unit's side along the box width, as placed."""
  widthCm: Float!
  """Distance along the box length, in centimetres."""
  x: Float!
  """Distance along the box width, in centimetres."""
  y: Float!
  """Height above the box floor, in centimetres."""
  z: Float!
}

"""
PRIMARY: the packing with the least chargeable weight. ALTERNATIVE: a packing with a different box count or mix, priced too; per service the cheaper is kept.
"""
enum PackingCandidate {
  """
  A packing with a different box count or mix, priced too. Per service the cheaper one is kept.
  """
  ALTERNATIVE
  """The packing with the least chargeable weight."""
  PRIMARY
}

"""One line resolved to base units with its per-unit size and weight."""
type PackingItem {
  """
  Packed apart from non-fragile items (Product.metadata.deliveryFlags.fragile).
  """
  fragile: Boolean!
  """The height, in centimetres."""
  heightCm: Float
  """The name of the item."""
  label: String!
  """The length, in centimetres."""
  lengthCm: Float
  """True when the item ships in its own packaging."""
  ownPackaging: Boolean!
  """Base units."""
  quantity: Float!
  """Where the size came from."""
  sizeSource: PackingValueSource!
  "The ID of the product variant."
  variantId: ID!
  """Per base unit; 0 when unknown."""
  weightKg: Float!
  """Where the weight came from."""
  weightSource: PackingValueSource!
  """The width, in centimetres."""
  widthCm: Float
}

"""
How admin screens show and accept box sizes and weights: METRIC (cm / kg) or IMPERIAL (in / lb). Values are always stored and sent in cm / kg.
"""
enum PackingMeasurementSystem {
  """Inches and pounds."""
  IMPERIAL
  """Centimetres and kilograms."""
  METRIC
}

"""One way of packing the goods into boxes."""
type PackingPlan {
  """How many boxes it uses."""
  boxCount: Int!
  """The boxes, with what is in each."""
  boxes: [PackedBox!]!
  """
  Staff only: what the plan's empty boxes cost (decimal string, organization base currency); null when no box of the plan has a cost. Never part of the customer's delivery fee.
  """
  totalBoxCost: String
  """
  The total chargeable weight, in kilograms: the larger of actual and volumetric weight per box.
  """
  totalChargeableWeightKg: Float!
  """The total weight, in kilograms."""
  totalWeightKg: Float!
}

"""A live price with the packing it was priced with."""
type PackingRateOption {
  """The price, as a decimal string in the rate's currency."""
  amount: String!
  """
  The price before the carrier's tax, as a decimal string. Only set when the partner reports it in the same currency.
  """
  amountExclTax: String
  """How many boxes the price is for."""
  boxCount: Int!
  """Which packing candidate the price was worked out for."""
  candidate: PackingCandidate!
  """The courier that would carry the shipment."""
  carrierName: String!
  "ISO 4217 currency code."
  currency: String!
  """The ID of the delivery partner the rate comes from."""
  deliveryPartnerConfigId: String!
  """The earliest expected delivery."""
  etaFrom: DateTime
  """The latest expected delivery."""
  etaTo: DateTime
  """When the price stops being valid."""
  expiresAt: DateTime
  """The parcels priced (cm / kg)."""
  parcels: [DeliveryParcelGql!]!
  """The name of the delivery partner."""
  partnerDisplayName: String!
  """The partner's logo, or empty to show a monogram."""
  partnerLogoUrl: String
  """
  The partner's reference for the quote, used when booking at this price.
  """
  providerQuoteRef: String
  """The code of the service level, as the partner names it."""
  serviceLevelCode: String!
  """The name of the service level."""
  serviceLevelName: String!
}

"""The packing and live prices for some lines and an address."""
type PackingRatePreview {
  """The currency the rates were asked in."""
  currency: String!
  """The name of the warehouse the goods leave."""
  originWarehouseName: String!
  """How the goods pack into boxes."""
  packing: PackingResult!
  """The prices on offer."""
  rates: [PackingRateOption!]!
  """The delivery partners that could not give a price, and why."""
  unavailable: [UnavailableDeliveryPartnerGql!]!
}

"""
What to pack and price: the lines and where they go. Give an address ID or the address fields.
"""
input PackingRatePreviewInput {
  """A saved address; or type one in the street/city fields."""
  addressId: ID
  """The city."""
  city: String
  """The country."""
  country: String
  """The lines to pack and price."""
  lines: [PackingRatePreviewLineInput!]!
  """Price from this warehouse; else the Default pickup warehouse."""
  originWarehouseId: ID
  """The postal code."""
  postalCode: String
  """The state or region."""
  state: String
  """The first line of the street address."""
  street1: String
  """The second line of the street address."""
  street2: String
}

"""One line to pack and price."""
input PackingRatePreviewLineInput {
  """The quantity."""
  quantity: Float!
  """The line's unit; omit for the base unit."""
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
}

"""The outcome of packing goods into boxes."""
type PackingResult {
  """A packing with a different box count or mix, or null."""
  alternative: PackingPlan
  """The variants whose size or weight was estimated."""
  estimatedVariantIds: [ID!]!
  """
  Packed weight is above the freight-quote weight: checkout gives no live price.
  """
  freightQuote: Boolean!
  """The items that were packed."""
  items: [PackingItem!]!
  """The variants that had no weight."""
  missingWeightVariantIds: [ID!]!
  """The packing with the least chargeable weight (ties → fewer boxes)."""
  primary: PackingPlan!
  """How the goods were packed."""
  strategy: PackingStrategy!
}

"""
BOXES: packed into the tenant's boxes. DEFAULT_PARCEL: the tenant has no enabled box — the delivery settings' single default parcel (unchanged behaviour). EMPTY: no lines. NO_BOX_FOR_PARTNER: boxes are enabled but none is open to the delivery partner asked about — it is not offered.
"""
enum PackingStrategy {
  """Packed into the organization's boxes."""
  BOXES
  """No box is enabled, so one default parcel is used."""
  DEFAULT_PARCEL
  """The order has no lines."""
  EMPTY
  """
  Boxes are enabled but none is open to the delivery partner, so it is not offered.
  """
  NO_BOX_FOR_PARTNER
}

"""
Where an item's weight or size came from: the variant, its category (or a parent), the packing default item, or nowhere (unknown).
"""
enum PackingValueSource {
  """Taken from the category or a parent category."""
  CATEGORY
  """Taken from the packing default item."""
  DEFAULT
  """Not known."""
  NONE
  """Taken from the variant."""
  VARIANT
}

"""Where a page sits in a list."""
type PageInfo {
  """The cursor of the last row on this page."""
  endCursor: String
  """True when there are more rows after this page."""
  hasNextPage: Boolean!
  """True when there are rows before this page."""
  hasPreviousPage: Boolean!
  """The cursor of the first row on this page."""
  startCursor: String
}

"""A page of stock rows."""
type PaginatedInventories {
  """The stock rows on this page."""
  items: [Inventory!]!
  """Where this page sits in the full result."""
  pageInfo: PageInfo!
  """How many stock rows match the filter in all."""
  totalCount: Int!
}

"""A page of settings."""
type PaginatedSettingsResponse {
  """True when there are more after this page."""
  hasNextPage: Boolean!
  """True when there are pages before this one."""
  hasPreviousPage: Boolean!
  """Where this page sits in the full result."""
  pageInfo: PageInfo!
  """The settings on this page."""
  settings: [TenantSetting!]!
  """How many settings match in all."""
  totalCount: Int!
}

"""A page of stock movements."""
type PaginatedStockMovements {
  """The stock movements on this page."""
  items: [StockMovement!]!
  """Where this page sits in the full result."""
  pageInfo: PageInfo!
  """How many stock movements match the filter in all."""
  totalCount: Int!
}

"""A page of users."""
type PaginatedUsersResponse {
  """True when there are more after this page."""
  hasNextPage: Boolean!
  """True when there are pages before this one."""
  hasPreviousPage: Boolean!
  """Where this page sits in the full result."""
  pageInfo: PageInfo!
  """How many users match in all."""
  totalCount: Int!
  """The users on this page."""
  users: [User!]!
}

"""Which page of a list to return."""
input PaginationInput {
  """Cursor for cursor-based pagination"""
  cursor: String
  """Items per page"""
  limit: Int! = 20
  """Page number (1-indexed)"""
  page: Int! = 1
}

"""Where a page sits in a list."""
type PaginationMeta {
  """How many rows per page."""
  limit: Int!
  """The page number."""
  page: Int!
  """How many rows there are in all."""
  total: Int!
  """How many pages there are."""
  totalPages: Int!
}

"""One line of a partial return."""
input PartialReturnItemInput {
  "The ID of the product."
  productId: String!
  """The quantity returned."""
  quantity: Float!
  """Why the goods are returned."""
  reason: String!
  "The ID of the product variant."
  variantId: String!
}

"""
A partner: the one master record for customers and vendors, with its roles, addresses, contacts and account details.
"""
type Partner {
  """The partner's addresses."""
  addresses: [PartnerAddress!]
  """The sales rep who owns the customer."""
  assignedSalesRep: CreatedByUser
  """The ID of the sales rep who owns the customer."""
  assignedSalesRepId: String
  """
  The customer's saved buying lists, counted: how many lists and how many items across them. A customer with no lists reads zero for both. Read-only: the lists belong to the buyer and are edited in the buyer app or portal.
  """
  buyingListSummary: PartnerBuyingListSummary!
  """The partner code."""
  code: String!
  """The partner's contacts."""
  contacts: [PartnerContact!]
  "When the record was created."
  createdAt: DateTime!
  """The user who created the partner."""
  createdByUser: CreatedByUser
  """The credit limit. 0 or less means unlimited."""
  creditLimit: Float!
  """The stored balance. It can drift, so prefer ledger."""
  currentBalance: Float!
  """The customer-side account details."""
  customerAccount: CustomerAccount
  """The email address of the customer's main contact."""
  customerEmail: String
  """The partner's tier label, set automatically or by hand."""
  customerTier: String
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the partner is."""
  description: String
  """The standing discount, in percent."""
  discountPercent: Float!
  """The name to show for the partner."""
  displayName: String
  """
  The customer's tier as it would be charged, with automatic tiering and this month's spend applied.
  """
  effectiveTier: EffectiveTierInfo
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """The partner's industry."""
  industry: String
  """The expected days from order to delivery."""
  leadTimeDays: Int!
  """Both sides of the partner's money position, worked out on every read."""
  ledger: PartnerLedger
  """The legal name of the partner."""
  legalName: String
  """
  The customer's lifetime order, invoice and payment figures, worked out from the documents.
  """
  lifetimeFacts: CustomerLifetimeFacts
  """The partner's loyalty points."""
  loyaltyPoints: Int!
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """The smallest order value."""
  minOrderValue: Float
  """The name of the partner."""
  name: String!
  """Notes about the partner."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """A discount that applies to the customer from another source."""
  otherApplicableDiscount: DiscountScheme
  """
  What is still owed to the vendor: the total outstanding on open purchase invoices, in the organization's base currency.
  """
  outstandingPayable: Float
  """The payment terms agreed with the partner."""
  paymentTerms: String!
  """
  The language of documents sent to the partner. Empty means the organization's default.
  """
  preferredLanguage: String
  """The rep the customer was moved away from."""
  previousSalesRep: CreatedByUser
  """The ID of the rep the customer was moved away from."""
  previousSalesRepId: String
  """The products the partner supplies or buys."""
  products: [PartnerProduct!]
  """A rating of the partner."""
  rating: Float
  """When the previous rep acknowledged the move."""
  reassignmentAcknowledgedAt: DateTime
  """The partner's company registration number."""
  registrationNumber: String
  """
  Which app the partner was created in, for example Admin Web or Sales App.
  """
  registrationSource: String
  """When the customer was moved to the current rep."""
  repReassignedAt: DateTime
  """The roles of the partner, such as customer or supplier."""
  roles: [PartnerRole!]!
  """
  True when the customer registered themselves instead of being created by staff.
  """
  selfRegistered: Boolean!
  """The status of the partner."""
  status: PartnerStatus!
  """Tags on the partner."""
  tags: [String!]!
  """The partner's tax ID."""
  taxId: String
  """The kind of partner."""
  type: PartnerType
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The vendor-side account details."""
  vendorAccount: VendorAccount
  """The partner's website."""
  website: String
}

"""An address of a partner."""
type PartnerAddress {
  """The city."""
  city: String!
  """The email address of the contact at the address."""
  contactEmail: String
  """The name of the contact at the address."""
  contactName: String
  """The phone number of the contact at the address."""
  contactPhone: String
  """The country."""
  country: String!
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """Delivery or access instructions."""
  instructions: String
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """True when the one address serves both billing and delivery."""
  isDualPurpose: Boolean!
  """A label for the address, such as Head office."""
  label: String
  """The latitude."""
  latitude: Float
  """The longitude."""
  longitude: Float
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  "The ID of the organization the record belongs to."
  organizationId: String!
  "The ID of the partner."
  partnerId: String!
  """The postal code."""
  postalCode: String!
  """Whether the address is the primary or a secondary one."""
  priority: AddressPriority!
  """Whether the address is for a customer or a vendor role."""
  role: PartnerRole
  """The state or region."""
  state: String!
  """The first line of the street address."""
  street1: String!
  """The second line of the street address."""
  street2: String
  """The kind of address, for example billing or shipping."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""
A customer's saved buying lists from the buyer app or portal, counted for the staff customer record: how many lists and how many items across them.
"""
type PartnerBuyingListSummary {
  """Items across all of those lists."""
  itemCount: Int!
  """Saved buying lists the customer keeps."""
  listCount: Int!
}

"""A customer's consent picture."""
type PartnerConsentGql {
  """The consents recorded."""
  consents: [ContactConsentGql!]!
  """True when staff flagged the customer as never to receive marketing."""
  doNotMarket: Boolean!
  """
  The ID of the contact marketing is actually sent to. Empty when the customer has none.
  """
  messageContactId: ID
}

"""A contact of a partner."""
type PartnerContact {
  """Full display name, kept as `First Last`."""
  contactName: String
  """The person's job title."""
  contactTitle: String
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The person's department."""
  department: String
  "The ID of the user who created the record."
  enteredBy: String!
  """The person's first name."""
  firstName: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """A label for the contact."""
  label: String
  """The person's last name."""
  lastName: String
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """Notes about the contact."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  "The ID of the partner."
  partnerId: String!
  """The best time to reach them."""
  preferredTime: String
  """Whether this is the primary or a secondary contact."""
  priority: String!
  """
  The contact PERSON's permanent reference — `<partner code>-<8 hex>`, e.g. `C000110-a3f91b7e`. Minted once at creation from a random UUID and STORED, so it survives every later edit to the person's name, email, phone or title. Replaces the old `<code>@<firstnamelastname>` string, which was derived on read and so was neither unique (two people with one name collided) nor stable (a typo fix changed it). Shared by every CHANNEL row of one person (phone/whatsapp/email), because it identifies the person, not the row — so it is deliberately NOT unique per row. Round-trip it on update: a save that omits it falls back to matching the row by id or by type+value. Null for a partner with no code. NOTE: this type is a near-duplicate of `Contact` (pre-existing debt) — a field added to one almost always belongs on both.
  """
  referenceId: String
  """Their time zone."""
  timeZone: String
  """The kind of contact, for example email or phone."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """
  The customer login (User.userType = CUSTOMER) this contact person IS. Re-resolved by name match on every partner write — never settable by the client. Null for the majority of contacts, who are not portal users.
  """
  userId: ID
  """The email address or phone number."""
  value: String!
}

"""
One row of a customer's Users tab on the partner record: a buyer login.
"""
type PartnerCustomerUser {
  """
  approver reach — COMPANY (every request at this partner, incl. branchless ones) | BRANCH (only the branches granted in `addresses`). Meaningful only when approvesOrders; an Owner is always company-wide.
  """
  approverScope: String!
  """
  User.approvesCustomerOrders — may decide teammates' parked over-limit orders. Always true for an Owner (that is what owning the account means).
  """
  approvesOrders: Boolean!
  """
  Addresses assigned to this user. Meaning depends on `role` — for CUSTOMER_ADMIN, empty means UNRESTRICTED (whole account address book); for CUSTOMER_BUYER / CUSTOMER_VIEWER, empty means NONE assigned (denied, per resolveAddressScope). On the list so the Users tab can show each login's reach without opening every row.
  """
  assignedAddressIds: [ID!]!
  "When the record was created."
  createdAt: DateTime!
  "Email address."
  email: String!
  """The person's first name."""
  firstName: String!
  "The unique ID of this record."
  id: ID!
  """
  PENDING (invited, not yet accepted) | ACTIVE (accepted + enabled) | DEACTIVATED (accepted, access revoked).
  """
  inviteStatus: String!
  """When the person last signed in."""
  lastLoginAt: DateTime
  """The person's last name."""
  lastName: String!
  """
  Per-order ceiling in the org base currency (User.customerOrderLimit). Null = no limit. Only bites in Company mode — in branch mode the BRANCH's own orderLimit is the only value limit (rule 1), and an Owner is never order-value checked at all.
  """
  orderLimit: Float
  """
  Reference id shown in the admin console — `<customer code>@<firstnamelastname>` (e.g. C000049@gowrivijayan). DERIVED on read from Partner.code + the user's name, not a stored column, and not unique — display only, never a lookup key. Empty string when the partner has no code or the user has no name.
  """
  referenceId: String!
  """
  CUSTOMER_ADMIN (Owner) | CUSTOMER_BUYER | CUSTOMER_VIEWER — the SAME vocabulary the buyer-side team screen uses (CUSTOMER_TEAM_ROLES). The founding self-registered user is CUSTOMER_ADMIN; invited users hold whatever role the invite carried (default CUSTOMER_BUYER).
  """
  role: String!
  """
  The raw User.status — ACTIVE | INACTIVE (invite outstanding) | SUSPENDED (access revoked). Prefer `inviteStatus`, which reads the same row as the three states the UI shows.
  """
  status: String!
}

"""
Everything the account owner assigned to one buyer login, in one payload.
"""
type PartnerCustomerUserDetail {
  """
  Every LIVE address of the partner, flagged with this user's assignment and approver grant. This is the seller's full view of the account address book — it is deliberately NOT narrowed to what the user may use, because it also seeds the assignment checkboxes.
  """
  addresses: [CustomerUserAddressAssignment!]!
  """
  approver reach — COMPANY (every request at this partner, incl. branchless ones) | BRANCH (only the branches granted in `addresses`). Meaningful only when approvesOrders; an Owner is always company-wide.
  """
  approverScope: String!
  """
  User.approvesCustomerOrders — may decide teammates' parked over-limit orders. Always true for an Owner (that is what owning the account means).
  """
  approvesOrders: Boolean!
  """
  Addresses assigned to this user. Meaning depends on `role` — for CUSTOMER_ADMIN, empty means UNRESTRICTED (whole account address book); for CUSTOMER_BUYER / CUSTOMER_VIEWER, empty means NONE assigned (denied, per resolveAddressScope). On the list so the Users tab can show each login's reach without opening every row.
  """
  assignedAddressIds: [ID!]!
  "When the record was created."
  createdAt: DateTime!
  "Email address."
  email: String!
  """The person's first name."""
  firstName: String!
  "The unique ID of this record."
  id: ID!
  """
  PENDING (invited, not yet accepted) | ACTIVE (accepted + enabled) | DEACTIVATED (accepted, access revoked).
  """
  inviteStatus: String!
  """When the person last signed in."""
  lastLoginAt: DateTime
  """The person's last name."""
  lastName: String!
  """
  Per-order ceiling in the org base currency (User.customerOrderLimit). Null = no limit. Only bites in Company mode — in branch mode the BRANCH's own orderLimit is the only value limit (rule 1), and an Owner is never order-value checked at all.
  """
  orderLimit: Float
  """The partner this login belongs to."""
  partnerId: ID!
  """
  Reference id shown in the admin console — `<customer code>@<firstnamelastname>` (e.g. C000049@gowrivijayan). DERIVED on read from Partner.code + the user's name, not a stored column, and not unique — display only, never a lookup key. Empty string when the partner has no code or the user has no name.
  """
  referenceId: String!
  """
  CUSTOMER_ADMIN (Owner) | CUSTOMER_BUYER | CUSTOMER_VIEWER — the SAME vocabulary the buyer-side team screen uses (CUSTOMER_TEAM_ROLES). The founding self-registered user is CUSTOMER_ADMIN; invited users hold whatever role the invite carried (default CUSTOMER_BUYER).
  """
  role: String!
  """
  The raw User.status — ACTIVE | INACTIVE (invite outstanding) | SUSPENDED (access revoked). Prefer `inviteStatus`, which reads the same row as the three states the UI shows.
  """
  status: String!
}

"""Filters for the partner list."""
input PartnerFilterInput {
  """
  Only partners owned by this user. Send UNASSIGNED for partners with no owner. It narrows the scope the server already applies and never widens it.
  """
  assignedSalesRepId: ID
  """Only partners with one of these roles."""
  roles: [PartnerRole!]
  "Text to search for."
  search: String
  """
  Match the search against the partner's name, code and tax ID only, not its contacts.
  """
  searchNameOnly: Boolean
  """Only partners in this status."""
  status: PartnerStatus
  """Only partners with one of these tags."""
  tags: [String!]
  """
  Only customers whose effective tier has this key, with automatic tiering applied.
  """
  tierKey: String
  """Only partners of this kind."""
  type: String
}

"""
A partner's money position on both sides, since one partner can be both customer and vendor. It is worked out on every read and never stored.
"""
type PartnerLedger {
  """What the partner owes as a customer."""
  asCustomer: PartnerLedgerSide!
  """What is owed to the partner as a vendor."""
  asSupplier: PartnerLedgerSide!
}

"""
One side of a partner's money position, as unsigned figures pointing in opposite directions.
"""
type PartnerLedgerSide {
  """Cash paid but not yet allocated, sitting on account."""
  advances: Float!
  """Advances plus note credits: the credit held in the other direction."""
  creditOnAccount: Float!
  """
  Unapplied note credit: credit notes for a customer, debit notes for a vendor.
  """
  noteCredits: Float!
  """
  The total outstanding on open invoices on this side, in the organization's base currency. A receivable on the customer side, a payable on the vendor side.
  """
  outstanding: Float!
  """
  The part of the outstanding amount already past due. It is a part of it, not extra.
  """
  overdue: Float!
}

"""A product a partner supplies or buys, with its terms and history."""
type PartnerProduct {
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """True when this is a preferred product for the partner."""
  isPreferred: Boolean!
  """The date of the last purchase."""
  lastPurchaseDate: DateTime
  """The price on the last purchase."""
  lastPurchasePrice: Float
  """The date of the last sale."""
  lastSaleDate: DateTime
  """The price on the last sale."""
  lastSalePrice: Float
  """The expected days from order to delivery."""
  leadTimeDays: Int!
  """The largest quantity per order."""
  maxOrderQuantity: Float
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """The smallest quantity per order."""
  minOrderQuantity: Float!
  """Notes about the product."""
  notes: String
  """Orders must be a multiple of this quantity."""
  orderMultiple: Float!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The brand the partner sells it under."""
  partnerBrand: String
  "The ID of the partner."
  partnerId: String!
  """The partner's own name for the product."""
  partnerName: String
  """The partner's own code for the product."""
  partnerSku: String!
  """When the price starts to apply."""
  priceValidFrom: DateTime
  """When the price stops applying."""
  priceValidTo: DateTime
  "The ID of the product."
  productId: String!
  """The agreed price of one unit."""
  unitPrice: Float!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  "The ID of the product variant."
  variantId: String
}

"""
Role of partner (CUSTOMER, SUPPLIER, DISTRIBUTOR, MANUFACTURER, RESELLER)
"""
enum PartnerRole {
  """Buys from the organization."""
  CUSTOMER
  """Distributes goods."""
  DISTRIBUTOR
  """Makes goods."""
  MANUFACTURER
  """Resells goods."""
  RESELLER
  """Sells to the organization."""
  SUPPLIER
}

"""A column the partner list can be sorted by."""
enum PartnerSortField {
  """The partner code."""
  CODE
  """When the partner was created."""
  CREATED_AT
  """The partner name."""
  NAME
  """The partner status."""
  STATUS
  """When the partner was last changed."""
  UPDATED_AT
}

"""How to sort the partner list."""
input PartnerSortInput {
  """The column to sort by."""
  field: PartnerSortField!
  """The sort direction."""
  order: SortOrder!
}

"""Headline partner counts."""
type PartnerStatistics {
  """How many are active."""
  active: Int!
  """How many are customers."""
  customers: Int!
  """How many were added recently."""
  recent: Int!
  """How many are suppliers."""
  suppliers: Int!
  """How many partners there are."""
  total: Int!
  """How many are vendors."""
  vendors: Int!
}

"""Status of partner (ACTIVE, INACTIVE, PENDING_APPROVAL)"""
enum PartnerStatus {
  """Can trade."""
  ACTIVE
  """Switched off."""
  INACTIVE
  """Waiting for approval."""
  PENDING_APPROVAL
}

"""Type of business partner"""
enum PartnerType {
  """A business."""
  BUSINESS
  """A corporation."""
  CORPORATION
  """A customer."""
  CUSTOMER
  """A government body."""
  GOVERNMENT
  """An individual."""
  INDIVIDUAL
  """A limited liability company."""
  LLC
  """A non-profit organization."""
  NONPROFIT
  """Any other type."""
  OTHER
  """A partnership."""
  PARTNERSHIP
  """A premium customer."""
  PREMIUM
  """A supplier."""
  SUPPLIER
  """A vendor."""
  VENDOR
}

"""What the organization owes its vendors."""
type PayablesAnalytics {
  """Open bills by age."""
  aging: [AgingBucket!]!
  """
  The average days between a vendor bill's date and the payment allocated to it, for payments made in the range. Counts only bills that were paid, so it is not days payable outstanding. 0 when nothing was paid.
  """
  avgDaysToPayVendors: Float!
  """
  Days payable outstanding: open vendor bills at the end of the range ÷ vendor bills issued in the range × days in the range, to one decimal. Null when no vendor bill was issued in the range. Base currency; credit and debit notes are not netted.
  """
  dpoDays: Float
  """The vendors owed the most."""
  topCreditors: [DebtorSlice!]!
}

"""
A payment made out to a vendor or a collection received from a customer, with its allocations to invoices.
"""
type Payment {
  """The part of the payment applied to invoices so far."""
  allocatedAmount: Float!
  """
  Derived: AWAITING_ALLOCATION (unallocated cash, partner has open invoices), OVERPAID (excess beyond everything owed) or FULLY_ALLOCATED. Null for draft/cancelled/reversed/refunded payments.
  """
  allocationState: PaymentAllocationState
  """
  The allocations that apply this payment to invoices, including reversals.
  """
  allocations: [PaymentAllocation!]!
  """The payment amount, in currencyCode."""
  amount: Float!
  """
  True for a customer's portal bank transfer the seller has not accepted yet. Accepting it counts the money as received and posts it to the customer's balance once.
  """
  awaitingAcceptance: Boolean!
  """The ID of the bank account the payment moved through."""
  bankAccountId: String
  """The cheque date, for cheque payments."""
  checkDate: DateTime
  """The cheque number, for cheque payments."""
  checkNumber: String
  """When the record was created."""
  createdAt: DateTime!
  """Currency code of the payment amount."""
  currencyCode: String!
  """When the record was deleted. Null while it is active."""
  deletedAt: DateTime
  """The ID of the user who created the record."""
  enteredBy: String!
  """
  Exchange rate between the document currency and the organization's base currency, when they differ.
  """
  exchangeRate: Float
  """Unique identifier of the record."""
  id: ID!
  """The sales order this payment is tied to before it is invoiced, if any."""
  linkedOrder: SalesOrder
  """Notes on the document, visible to the customer."""
  notes: String
  """The ID of the organization (tenant) that owns the record."""
  organizationId: String!
  """The customer or supplier the payment is with."""
  partner: Partner
  """The ID of the customer or supplier the payment is with."""
  partnerId: String!
  """The date the payment was made."""
  paymentDate: DateTime!
  """How the payment was made. See PaymentMethod."""
  paymentMethod: PaymentMethod!
  """The human-readable payment number, unique within the organization."""
  paymentNumber: String!
  """
  The reference of the payment, such as a bank transfer or transaction reference.
  """
  referenceNumber: String
  """Where the payment is in its lifecycle. See PaymentStatus."""
  status: PaymentStatus!
  """
  COLLECTION for money received from a customer, PAYMENT for money paid to a supplier.
  """
  type: PaymentType!
  """The part of the payment not yet applied to any invoice."""
  unallocatedAmount: Float!
  """When the record was last changed."""
  updatedAt: DateTime!
  """The ID of the user who last changed the record."""
  updatedBy: String!
  """
  Optimistic-concurrency counter — pass back as expectedVersion on the next mutation.
  """
  version: Int!
}

"""The amount of one payment applied to one invoice."""
type PaymentAllocation {
  """
  The amount applied to the invoice. Negative on the counter-entry that reverses an earlier allocation.
  """
  amount: Float!
  """
  True when the allocation was applied after the payment was created, settling an invoice from cash held on account.
  """
  appliedFromAdvance: Boolean
  """When the allocation was created."""
  createdAt: DateTime!
  """Unique identifier of the record."""
  id: ID!
  """The ID of the invoice the amount was applied to."""
  invoiceId: ID!
  """The number of the invoice the amount was applied to."""
  invoiceNumber: String
  """The status of the invoice the amount was applied to."""
  invoiceStatus: String
  """The date of the payment."""
  paymentDate: DateTime
  """The ID of the payment this allocation belongs to."""
  paymentId: ID!
  """How the payment was made."""
  paymentMethod: String
  """The number of the payment this allocation belongs to."""
  paymentNumber: String
  """On a reversal counter-entry, the ID of the allocation it reverses."""
  reversalOfId: ID
  """When the allocation was reversed. Null if it was not."""
  reversedAt: DateTime
}

"""An amount of a payment applied to one invoice."""
input PaymentAllocationInput {
  """
  Amount to allocate, in the payment's currency. Must be greater than zero.
  """
  amount: Float!
  """Foreign-exchange gain or loss to record on this allocation."""
  forexGainLoss: Float
  """The ID of the invoice to allocate to."""
  invoiceId: ID!
}

"""
Derived, read-time classification of a payment's unallocated remainder: awaiting allocation (partner has open invoices) vs overpaid (excess beyond everything owed).
"""
enum PaymentAllocationState {
  """Not yet applied to any invoice."""
  AWAITING_ALLOCATION
  """All of it is applied to invoices."""
  FULLY_ALLOCATED
  """More was paid than the invoices need."""
  OVERPAID
}

"""A page of payments and the total number that match."""
type PaymentConnection {
  """The payments on this page."""
  payments: [Payment!]!
  """How many payments match the filter in all."""
  total: Int!
}

"""
The payments dashboard: headline totals, recent payments and breakdowns.
"""
type PaymentDashboard {
  """Daily cash movement over the last 30 days."""
  cashFlow: [CashFlowData!]!
  """The ten customers with the largest settled collections."""
  collectionsByCustomer: [CustomerCollection!]!
  """Settled payments grouped by payment method."""
  paymentsByMethod: [PaymentMethodBreakdown!]!
  """The ten most recent settled payments."""
  recentPayments: [Payment!]!
  """Headline payment figures."""
  summary: PaymentSummary!
}

"""Filters and sorting for the payment list."""
input PaymentFilterInput {
  """Only payments dated on or before this ISO 8601 date."""
  endDate: String
  """
  Splits the partially-allocated payments: true keeps only overpaid ones (cash left over that no open invoice can absorb), false drops them. Send with status PARTIAL. Omit for no constraint.
  """
  overpaid: Boolean
  """Only payments for this customer or supplier."""
  partnerId: ID
  """Only payments made this way."""
  paymentMethod: PaymentMethod
  """Text to search for in payments."""
  search: String
  """Field to sort by. Omitted means newest payment date first."""
  sortBy: PaymentSortField
  """Sort direction."""
  sortOrder: SortOrder
  """Only payments dated on or after this ISO 8601 date."""
  startDate: String
  """Only payments with this status."""
  status: PaymentStatus
  """
  Only payments of this type: COLLECTION (received) or PAYMENT (paid out).
  """
  type: PaymentType
}

"""
The organization's setup for one payment provider. Secret credentials are never returned.
"""
type PaymentGatewayConfigGql {
  """
  The secret credential fields that have a stored value. The values themselves are never returned.
  """
  configuredSecretKeys: [String!]!
  """The payment methods offered through this gateway."""
  enabledMethods: [String!]!
  """The provider environment the credentials belong to."""
  environment: PaymentGatewayEnvironment!
  "The unique ID of this record."
  id: ID!
  """True when the gateway is offered at checkout."""
  isEnabled: Boolean!
  """The non-secret credential fields with their values."""
  nonSecretValues: [CredentialValueGql!]!
  """The payment provider."""
  provider: PaymentGatewayProvider!
  "When the record was last changed."
  updatedAt: DateTime!
  """The result of the last verification."""
  verification: PaymentGatewayVerificationGql!
}

"""One credential a payment provider needs, such as an API key."""
type PaymentGatewayCredentialFieldGql {
  """Guidance on where to find the value."""
  helpText: String
  """The name of the credential field."""
  key: String!
  """The label to show for the field."""
  label: String!
  """An example value to show in the empty field."""
  placeholder: String
  """True when the value is a secret and is never returned once saved."""
  secret: Boolean!
}

"""Whether a payment gateway is in TEST or LIVE mode."""
enum PaymentGatewayEnvironment {
  """Real payments."""
  LIVE
  """Test payments."""
  TEST
}

"""A payment provider: STRIPE, RAZORPAY, PEACH or STITCH."""
enum PaymentGatewayProvider {
  """Peach Payments."""
  PEACH
  """Razorpay."""
  RAZORPAY
  """Stitch."""
  STITCH
  """Stripe."""
  STRIPE
}

"""
A payment provider the organization can connect, and the credentials it needs.
"""
type PaymentGatewayProviderInfo {
  """The credentials to collect for this provider."""
  credentialFields: [PaymentGatewayCredentialFieldGql!]!
  """The provider's name for display."""
  displayName: String!
  """The payment provider."""
  provider: PaymentGatewayProvider!
  """
  The webhook URL for this organization, to paste into the provider's dashboard.
  """
  webhookUrl: String!
}

"""
The result of checking a gateway's credentials, webhook and test payment.
"""
type PaymentGatewayVerificationGql {
  """When the credentials were last checked, as an ISO 8601 timestamp."""
  keysCheckedAt: String
  """True when the saved credentials were accepted by the provider."""
  keysValid: Boolean!
  """
  True when a credential edit disabled the gateway. Verify it again, then enable it.
  """
  needsReverification: Boolean!
  """When a test payment last succeeded, as an ISO 8601 timestamp."""
  testPaymentAt: String
  """True when the provider's webhook reached the API."""
  webhookReachable: Boolean!
}

"""
Totals for the payment list, counted over the whole filtered set in the organization's base currency. Only money that moved is included: not draft, cancelled, reversed or refunded payments, and not credit or debit note settlements.
"""
type PaymentListSummary {
  """Cash dated this month."""
  month: PaymentListSummaryBucket!
  """Cash dated today."""
  today: PaymentListSummaryBucket!
  """Cash across all time."""
  total: PaymentListSummaryBucket!
  """How many payments match the filter, drafts and cancelled included."""
  totalCount: Int!
  """
  The part of the total that no invoice has absorbed yet, in the base currency.
  """
  unallocatedAmount: Float!
  """Cash dated this week, counted from Sunday."""
  week: PaymentListSummaryBucket!
}

"""
Cash that moved in one time bucket, in the organization's base currency.
"""
type PaymentListSummaryBucket {
  """
  The total amount of cash payments dated in the bucket, in the base currency.
  """
  amount: Float!
  """How many cash payments are dated in the bucket."""
  count: Int!
}

"""
How a payment was made. DEBIT_NOTE and CREDIT_NOTE record settlements by note, not cash.
"""
enum PaymentMethod {
  """A bank transfer."""
  BANK_TRANSFER
  """Cash."""
  CASH
  """A cheque."""
  CHECK
  """A credit card."""
  CREDIT_CARD
  """A credit note."""
  CREDIT_NOTE
  """A debit card."""
  DEBIT_CARD
  """A debit note."""
  DEBIT_NOTE
  """A digital wallet."""
  DIGITAL_WALLET
  """A direct debit."""
  DIRECT_DEBIT
  """An online payment gateway."""
  ONLINE_GATEWAY
  """Any other method."""
  OTHER
  """A standing instruction to the bank."""
  STANDING_INSTRUCTION
}

"""Settled payments grouped by payment method."""
type PaymentMethodBreakdown {
  """The total for this method, in the organization's base currency."""
  amount: Float!
  """How many settled payments used this method."""
  count: Int!
  """The payment method, or Unknown when none was recorded."""
  method: String!
}

"""A column the payment list can be sorted by."""
enum PaymentSortField {
  """The payment amount."""
  AMOUNT
  """The payment date."""
  PAYMENT_DATE
  """When the payment was last changed."""
  UPDATED_AT
}

"""
Where a payment, or an order's payment, stands in its lifecycle, from draft through settlement to cancelled or reversed.
"""
enum PaymentStatus {
  """Approved."""
  APPROVED
  """Cancelled."""
  CANCELLED
  """Not yet submitted."""
  DRAFT
  """Past its due date."""
  OVERDUE
  """Paid in full."""
  PAID
  """Partly paid."""
  PARTIAL
  """Waiting to be paid."""
  PENDING
  """Waiting for approval."""
  PENDING_APPROVAL
  """Processed."""
  PROCESSED
  """Refunded."""
  REFUNDED
  """Reversed."""
  REVERSED
}

"""
Headline payment figures for the payments dashboard, in the organization's base currency.
"""
type PaymentSummary {
  """How many settled collections were received."""
  collectionsCount: Int!
  """
  The amount still owed on pending invoices that are past their due date.
  """
  overdueAmount: Float!
  """How many pending invoices are past their due date."""
  overdueCount: Int!
  """How many settled payments were made out."""
  paymentsCount: Int!
  """The amount still owed on pending invoices."""
  pendingInvoicesAmount: Float!
  """How many invoices are pending."""
  pendingInvoicesCount: Int!
  """The total of settled collections received from customers."""
  totalCollections: Float!
  """The total of settled payments made out, such as supplier payments."""
  totalPayments: Float!
}

"""
An organization's payment term, such as Net 30, that sets when an invoice is due.
"""
type PaymentTerm {
  """Tenant-authored storage code, e.g. NET_30 or EOM_15."""
  code: String!
  "When the record was created."
  createdAt: DateTime
  """Free-text note about the term."""
  description: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """
  True when this row is served from the platform default set because the organization has not customized its terms yet. Such a row has no database id and cannot be updated until it is materialized.
  """
  isPlatformDefault: Boolean!
  """
  What the term does: NET gives a credit period of netDays, COD and PREPAID have none.
  """
  kind: PaymentTermKind!
  """Tenant-editable display text, e.g. 'Net 30'."""
  label: String!
  """The only input to due-date math: dueDate = invoiceDate + netDays."""
  netDays: Int!
  """The position of the term in lists, lowest first."""
  sortOrder: Int!
  "When the record was last changed."
  updatedAt: DateTime
}

"""
What a payment term does, as opposed to what it is called. NET carries a credit clock of netDays; COD and PREPAID are both netDays 0.
"""
enum PaymentTermKind {
  """Cash on delivery. Credit days are 0."""
  COD
  """Payment is due after a number of credit days."""
  NET
  """Payment is due before the order ships. Credit days are 0."""
  PREPAID
}

"""
Whether a payment is money going out or money coming in. PAYMENT is made out to a vendor, COLLECTION is received from a customer.
"""
enum PaymentType {
  """Money received from a customer."""
  COLLECTION
  """Money paid to a supplier."""
  PAYMENT
}

"""
What a bulk pending action works on. Give exactly one form: an explicit list of customer IDs, all of one rep's queue with the rep ID, or all of the unassigned group.
"""
input PendingBulkTargetInput {
  """True to act on a whole queue."""
  all: Boolean
  """The IDs of the customers."""
  customerIds: [ID!]
  """The ID of the rep whose whole queue to act on, with all."""
  repId: ID
  """True to act on the whole unassigned group, with all."""
  unassigned: Boolean
}

"""
A customer awaiting approval, reduced to what a new-arrival notice needs.
"""
type PendingCustomerSummaryItem {
  """
  The ID of the user who created the customer. A fixed marker for self-registered buyers.
  """
  createdById: String
  "The unique ID of this record."
  id: ID!
  """The name of the customer."""
  name: String!
}

"""How many customers await approval, with the newest few."""
type PendingCustomersSummary {
  """How many customers await approval in the organization."""
  count: Int!
  """
  The newest waiting customers, capped, to spot new arrivals between checks.
  """
  recent: [PendingCustomerSummaryItem!]!
}

"""A person who signed in with Google and still needs to sign up."""
type PendingGoogleUser {
  """The URL of the person's picture."""
  avatar: String
  "Email address."
  email: String!
  """The person's name."""
  name: String
}

"""The pending customers of one rep, or the unassigned group."""
type PendingRepGroup {
  """When the oldest waiting customer was submitted, as a sign of priority."""
  oldestSubmittedAt: DateTime
  """How many customers are waiting."""
  pendingCount: Int!
  """How many the rep created."""
  repCreatedCount: Int!
  """The email address of the rep."""
  repEmail: String
  """The ID of the owning rep. Empty for the unassigned group."""
  repId: ID
  """
  The name of the rep. Empty for the unassigned group or when the user no longer exists.
  """
  repName: String
  """How many registered themselves."""
  selfRegisteredCount: Int!
}

"""How the system and its users are performing."""
type PerformanceAnalytics {
  """How the API is performing."""
  apiMetrics: ApiMetrics!
  """How the database is performing."""
  databaseMetrics: DatabaseMetrics!
  """Efficiency and goal figures."""
  performanceMetrics: PerformanceMetrics!
  """The health of the system."""
  systemHealth: SystemHealth!
  """How active users are."""
  userActivity: UserActivity!
}

"""Efficiency and goal figures, each with its trend."""
type PerformanceMetrics {
  """The efficiency score."""
  efficiencyScore: Float!
  """How the efficiency score is moving."""
  efficiencyTrend: Float!
  """How much of the goal was reached, in percent."""
  goalAchievement: Float!
  """How goal achievement is moving."""
  goalTrend: Float!
  """The productivity score."""
  productivity: Float!
  """How productivity is moving."""
  productivityTrend: Float!
  """The response time."""
  responseTime: Float!
  """How the response time is moving."""
  responseTimeTrend: Float!
}

"""An amount for one period."""
type PeriodAmount {
  """The amount."""
  amount: Float!
  """The period."""
  period: String!
}

"""Sales and orders for one period."""
type PeriodData {
  """How many orders."""
  orders: Int!
  """The period."""
  period: String!
  """The sales value."""
  sales: Float!
}

"""A permission."""
type Permission {
  """What it lets someone do."""
  action: String!
  "When the record was created."
  createdAt: DateTime!
  """What the permission allows."""
  description: String
  """
  True when it was granted directly to the user and can be removed. Set only when listing a user's permissions.
  """
  direct: Boolean
  """
  The role the permission comes from, when it is inherited and read-only.
  """
  fromRole: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """True when the permission is built in."""
  isSystem: Boolean!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The module the permission is in."""
  module: String!
  """The name of the permission."""
  name: String!
  """The kind of record it is on."""
  resource: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A group of permissions for one module."""
type PermissionGroup {
  """What the module's permissions cover."""
  description: String
  """The name to show."""
  displayName: String!
  """The icon of the module."""
  icon: String
  """The module."""
  module: String!
  """The permissions, grouped by kind of record."""
  resources: [PermissionResource!]!
  """The position of the group, lowest first."""
  sortOrder: Int!
}

"""The permissions on one kind of record."""
type PermissionResource {
  """How many permissions there are."""
  count: Int!
  """The permissions."""
  permissions: [Permission!]!
  """The kind of record."""
  resource: String!
}

"""The hours a partner collects, in 24 hour HH:mm."""
type PickupWindowHours {
  """The start of the collection hours."""
  from: String!
  """The end of the collection hours."""
  to: String!
  """The time zone the hours are in."""
  zone: String!
}

"""What a partner requires of a pickup window."""
type PickupWindowRules {
  """The hours the partner collects, on one day. Empty means any time."""
  hours: PickupWindowHours
  """The window may start no more than this many days ahead."""
  maxDaysAhead: Int!
  """The window must last at least this many minutes."""
  minDurationMinutes: Int!
  """The window may start no sooner than this many minutes from now."""
  minLeadMinutes: Int!
}

"""Places an order from the cart."""
input PlaceOrderFromCartInput {
  "The ID of the address."
  addressId: ID!
  """
  the chosen live delivery option id (customerDeliveryOptions / mobileDeliveryOptions). Required when the store prices delivery live; ignored otherwise.
  """
  deliveryOptionId: ID
  """CAS guard: the cart revision checkout was read against."""
  expectedRevision: Int
  """
  A unique key. Sending the same key again returns the order already placed instead of a duplicate.
  """
  idempotencyKey: String
  """Notes on the order."""
  notes: String
  """checkout payment method (null = legacy behaviour)."""
  paymentMethod: CustomerPaymentMethod
  """Buyer PO number → SalesOrder.customerPoNumber."""
  poNumber: String
  """
  The buyer's own reference for the order, such as a purchase order number.
  """
  reference: String
}

"""The result of placing an order from the cart."""
type PlaceOrderFromCartResult {
  """Set ONLY when the checkout parked for approval (screen 14)."""
  approvalRequest: CustomerApprovalRequestSummary
  "ISO 4217 currency code."
  currency: String!
  """
  The ID of the order. Empty when the checkout was sent for approval instead of becoming an order.
  """
  orderId: ID
  """The number of the order. Empty when sent for approval."""
  orderNumber: String
  """Resulting SalesOrderStatus (null on the approval branch).."""
  status: String
  """The total of the order. Empty when sent for approval."""
  totalAmount: Float
}

"""Places an order from the cart."""
input PlaceOrderInput {
  "The ID of the address."
  addressId: ID!
  """
  the chosen live delivery option id (mobileDeliveryOptions). Required when the store prices delivery live; ignored otherwise.
  """
  deliveryOptionId: ID
  """
  Idempotency key for retry safety. Must be `${cartId}-${ISO timestamp}`. Reuse on retry.
  """
  idempotencyKey: String!
  """
  Ignored. The printed-invoice fee was removed; kept so existing app builds that send it keep working.
  """
  includePrintedInvoice: Boolean = false
  """The ID of the delivery slot."""
  slotId: ID
}

"""
A courier service staff chose for an order: the delivery partner, the carrier and its service level.
"""
type PlannedCourierService {
  """Name of the carrier that delivers the order."""
  carrierName: String!
  """The ID of the delivery partner configuration the rate came from."""
  deliveryPartnerConfigId: String!
  """
  The partner's display name when the change was made. Null when unknown.
  """
  partnerDisplayName: String
  """Key of the shipping provider that quoted the service."""
  providerKey: String!
  """The carrier's code for the service level."""
  serviceLevelCode: String!
  """Display name of the service level."""
  serviceLevelName: String!
}

"""The portal settings, for the admin console."""
type PortalConfigResponse {
  """The accent colour."""
  accentColor: String!
  """True when customers can order directly."""
  allowDirectOrders: Boolean!
  """True when visitors can browse without signing in."""
  allowGuestBrowsing: Boolean!
  """True when customers can request quotes."""
  allowQuoteRequests: Boolean!
  """True when customers can register themselves."""
  allowSelfRegistration: Boolean!
  """True when customer orders go through the buyer-side approval workflow."""
  approvalWorkflowEnabled: Boolean!
  """The URL of the portal favicon."""
  faviconUrl: String
  "The unique ID of this record."
  id: ID!
  """True when the portal is switched on."""
  isEnabled: Boolean!
  """The URL of the portal logo."""
  logoUrl: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """
  The image shown wherever a product, category or other catalog image is missing.
  """
  placeholderImageUrl: String
  """The name shown on the portal."""
  portalName: String
  """The address of the portal."""
  portalUrl: String!
  """The main brand colour."""
  primaryColor: String!
  """
  The logo shown, taken from the organization when no portal logo is set.
  """
  resolvedLogoUrl: String
  """
  The name shown, taken from the organization when no portal name is set.
  """
  resolvedName: String!
  """True when stock levels are shown."""
  showInventory: Boolean!
  """True when prices are shown."""
  showPricing: Boolean!
  """The subdomain of the portal."""
  subdomain: String!
  """The support email address."""
  supportEmail: String
  """The support phone number."""
  supportPhone: String
  """The welcome message on the portal."""
  welcomeMessage: String
}

"""
What kind of portal host name it is: PLATFORM_SUBDOMAIN, set up when the organization is created, or CUSTOM, a domain the customer owns.
"""
enum PortalDomainKind {
  """A domain owned by the organization."""
  CUSTOM
  """A subdomain of the platform's domain."""
  PLATFORM_SUBDOMAIN
}

"""
Where a portal domain stands: PENDING while verification or the certificate is awaited, ACTIVE, FAILED, or DISABLED.
"""
enum PortalDomainStatus {
  """Live and serving the portal."""
  ACTIVE
  """Switched off."""
  DISABLED
  """Setup failed."""
  FAILED
  """Waiting for setup to finish."""
  PENDING
}

"""
self-registration result. Uniform whether or not the email already exists (no account enumeration).
"""
type PortalRegisterAccountResult {
  """A message about the outcome."""
  message: String!
  """True when the account waits for the seller's approval."""
  pendingApproval: Boolean!
}

"""Which buyer surface a home feed is for: the APP or the PORTAL."""
enum PortalSurface {
  """The buyer app."""
  APP
  """The customer web portal."""
  PORTAL
}

"""A price range."""
input PriceRangeInput {
  """The highest price."""
  max: Float
  """The lowest price."""
  min: Float
}

"""What to do with a return: approve it, reject it, or process it."""
enum ProcessAction {
  """Approve the return."""
  APPROVE
  """Process the return."""
  PROCESS
  """Reject the return."""
  REJECT
}

"""A refund for a return."""
input ProcessRefundInput {
  """The amount to refund."""
  amount: Float!
  """How the refund is paid."""
  method: RefundMethod!
}

"""Approves, rejects or processes a return."""
input ProcessReturnInput {
  """What to do with the return."""
  action: ProcessAction!
  """The credit note to raise, for a sales return."""
  creditNoteDetails: CreditNoteDetailsInput
  """The debit note to raise, for a purchase return."""
  debitNoteDetails: DebitNoteDetailsInput
  """What happens to each line."""
  processedItems: [ProcessedItemInput!]!
  """The ID of the return."""
  returnId: String!
}

"""The result of processing a return."""
type ProcessReturnResponse {
  """The ID of the credit note raised, if any."""
  creditNoteId: String
  """The ID of the debit note raised, if any."""
  debitNoteId: String
  """A message about the outcome."""
  message: String!
  """The return after processing."""
  updatedReturn: ProductReturn!
}

"""What happens to one return line when the return is processed."""
input ProcessedItemInput {
  """The quantity accepted."""
  acceptedQuantity: Float!
  """Why rejected stock is disposed of."""
  disposalReason: String
  """The ID of the return line."""
  itemId: String!
  """The quantity rejected."""
  rejectedQuantity: Float!
  """True when the accepted quantity goes back into inventory."""
  restockable: Boolean!
}

"""Purchasing figures from order to payment."""
type ProcureToPayAnalytics {
  """The average days between stages."""
  avgLeadTimeDays: LeadTimes!
  """The funnel from purchase order to payment."""
  funnel: [FunnelStage!]!
  """The share of receipts that arrived on time, in percent."""
  onTimeReceiptPct: Float!
  """The value of open purchase orders."""
  openPoValue: Float!
  """
  Values over the period, in the quote-to-cash trend shape: quotes is the purchase order value, orders the goods receipt value, invoiced the billed value and collected the paid value.
  """
  trend: [TrendPoint!]!
}

"""
A product: the master record with its variants, categories, units of measure and stock.
"""
type Product {
  """
  The price worked out from the default variant, or the first active variant.
  """
  basePrice: Float
  """The base unit of measure."""
  baseUOM: UnitOfMeasure
  """The ID of the base unit of measure."""
  baseUOMId: ID
  """The brand."""
  brand: Brand
  "The ID of the brand."
  brandId: ID
  """The categories the product is in."""
  categories: [ProductCategory!]
  """The main category."""
  category: Category
  "The ID of the category."
  categoryId: ID
  """The IDs of the categories the product is in."""
  categoryIds: [String!]
  "When the record was created."
  createdAt: DateTime!
  """The SKU of the default variant."""
  defaultVariantSku: String
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  """What the product is."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The URLs of the product images."""
  imageUrls: [String!]!
  """The stock of the product, one entry per warehouse."""
  inventory: [ProductInventory!]
  """The unit of measure stock is kept in."""
  inventoryUOM: UnitOfMeasure
  """The ID of the unit of measure stock is kept in."""
  inventoryUOMId: ID
  """True when the product is exempt from tax."""
  isTaxExempt: Boolean!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The name of the product."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The units of measure the product is sold in, with their prices."""
  productUOMs: [ProductUOMEntry!]
  """
  The tax group used when buying the product. Empty means the product follows the organization's default purchase tax group.
  """
  purchaseTaxGroupId: String
  """The tax rates applied when buying the product."""
  purchaseTaxRates: [TaxRate!]
  """The unit of measure used for purchases."""
  purchaseUOM: UnitOfMeasure
  """The ID of the unit of measure used for purchases."""
  purchaseUOMId: ID
  """The unit of measure used for sales."""
  salesUOM: UnitOfMeasure
  """The ID of the unit of measure used for sales."""
  salesUOMId: ID
  """The SKU of the default variant."""
  sku: String
  """The status of the product."""
  status: ProductStatus!
  """Tags on the product."""
  tags: [String!]!
  """Why the product is exempt from tax."""
  taxExemptReason: String
  "The ID of the tax group."
  taxGroupId: String @deprecated(reason: "Use taxGroupIds instead")
  """
  The IDs of the tax groups on the product, as one comma-separated string.
  """
  taxGroupIds: String
  """The tax rate on the product."""
  taxRate: TaxRate
  """The ID of the tax rate on the product. Use taxRateIds instead."""
  taxRateId: String @deprecated(reason: "Use taxRateIds instead")
  """
  The IDs of the tax rates on the product, as one comma-separated string.
  """
  taxRateIds: String
  """The tax rates on the product."""
  taxRates: [TaxRate!]
  "When the record was last changed."
  updatedAt: DateTime!
  """How many variants the product has."""
  variantCount: Int!
  """The variants of the product."""
  variants: [ProductVariant!]
}

"""A product attribute and its values."""
type ProductAttribute {
  """
  The spelling most variants use; spellings that differ only by case or spacing are one attribute.
  """
  key: String!
  """How many active products carry it (any of its values)."""
  productCount: Int!
  """Its values in natural order."""
  values: [ProductAttributeValue!]!
  """True when more values exist than were returned."""
  valuesTruncated: Boolean!
  """How many active variants carry it."""
  variantCount: Int!
}

"""What an attribute change did."""
type ProductAttributeChangeResult {
  """
  Labels of the product finders left unchanged because the change would break them; fix these in the finder editor.
  """
  findersNeedingAttention: [String!]!
  """Labels of the product finders rewritten."""
  findersUpdated: [String!]!
  """How many variants were rewritten."""
  variantsUpdated: Int!
}

"""Where an attribute, or one value of it, is used."""
type ProductAttributeUsage {
  """Labels of the product finders that name it."""
  finders: [String!]!
  """How many products those variants belong to."""
  productCount: Int!
  """How many variants (of products not deleted, active or not) carry it."""
  variantCount: Int!
}

"""One value of a product attribute."""
type ProductAttributeValue {
  """The picture set for the value, or null when none is."""
  imageUrl: String
  """The value as variants carry it."""
  value: String!
  """How many active variants carry it."""
  variantCount: Int!
}

"""A product or variant that could not be deleted."""
type ProductBulkDeleteFailure {
  """Why: NOT_FOUND, LAST_VARIANT or ERROR."""
  code: String!
  "The unique ID of this record."
  id: ID!
  """What went wrong."""
  message: String!
  """The name of the product or variant."""
  name: String
  """The SKU."""
  sku: String
}

"""
A product whose every live variant was selected. Those selections are skipped so a product is never left empty.
"""
type ProductBulkDeleteLastVariantViolation {
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
}

"""
What a bulk delete would affect, for the confirmation dialog. It writes nothing.
"""
type ProductBulkDeletePreview {
  """How many buyer buying list lines would be removed."""
  buyingListLines: Int!
  """How many buyer cart lines would be removed."""
  cartLines: Int!
  """
  In variant mode, how many selected variants are their product's default.
  """
  defaultVariantCount: Int!
  """Products whose every live variant is selected. Those are skipped."""
  lastVariantViolations: [ProductBulkDeleteLastVariantViolation!]!
  """
  How many requested IDs were not found, from another organization or already deleted.
  """
  missing: Int!
  """How many lines on open sales orders refer to what would be deleted."""
  openOrderLines: Int!
  """How many lines on open quotes refer to what would be deleted."""
  openQuoteLines: Int!
  """How many products were found in the organization."""
  productCount: Int!
  """How many live variants would be soft-deleted."""
  variantCount: Int!
}

"""A bulk product delete and how far it has got."""
type ProductBulkOperation {
  "When the record was created."
  createdAt: DateTime!
  """An error that stopped the whole operation."""
  error: String
  """How many failed."""
  failed: Int!
  """The items that failed, and why."""
  failures: [ProductBulkDeleteFailure!]!
  """When it finished."""
  finishedAt: DateTime
  "The unique ID of this record."
  id: ID!
  """How many it has handled."""
  processed: Int!
  """When it started."""
  startedAt: DateTime
  """Where the operation stands."""
  status: ProductBulkOperationStatus!
  """How many it deleted."""
  succeeded: Int!
  """How many items it covers."""
  total: Int!
  """What the operation does."""
  type: ProductBulkOperationType!
}

"""Where a bulk product operation stands."""
enum ProductBulkOperationStatus {
  """Finished with no errors."""
  COMPLETED
  """Finished, but some items failed."""
  COMPLETED_WITH_ERRORS
  """Stopped with an error."""
  FAILED
  """Waiting to start."""
  QUEUED
  """In progress."""
  RUNNING
}

"""What a bulk product operation does."""
enum ProductBulkOperationType {
  """Delete products in bulk."""
  PRODUCT_BULK_DELETE
  """Delete variants in bulk."""
  VARIANT_BULK_DELETE
}

"""
What to bulk delete. Give exactly one form: an explicit list of product IDs, or all with a filter and the expected total.
"""
input ProductBulkTargetInput {
  """True to delete everything that matches the filter."""
  all: Boolean
  """
  How many products the filter is expected to match. The delete is refused if the count differs.
  """
  expectedTotal: Int
  """The list filter that selects the products, when all is true."""
  filter: ProductFilterInput
  """
  A unique key per confirm click. Sending the same key again returns the existing operation instead of deleting twice.
  """
  idempotencyKey: String
  """
  The IDs of the products to delete. The number is capped, and each ID is checked against the organization.
  """
  productIds: [ID!]
}

"""A category a product is in."""
type ProductCategory {
  """The category."""
  category: Category!
  "The ID of the category."
  categoryId: String!
  "The unique ID of this record."
  id: ID!
  """True when this is the product's main category."""
  isPrimary: Boolean!
  "The ID of the product."
  productId: String!
}

"""A page of products."""
type ProductConnection {
  """True when there are more products after this page."""
  hasNextPage: Boolean!
  """The products on this page."""
  items: [Product!]!
  """The cursor to pass to get the next page."""
  nextCursor: String
  """How many products match the filter in all."""
  totalCount: Int!
}

"""
A product's delivery flags (Product.metadata.deliveryFlags), for every variant: own packaging and fragile. Null = not set.
"""
type ProductDeliveryFlags {
  """
  Own packaging as the product's primary category chain sets it (nearest first); null when no category sets it.
  """
  categoryOwnPackaging: Boolean
  """
  What packing uses: the product's own setting, else the category's, else false.
  """
  effectiveOwnPackaging: Boolean!
  """
  Packed only with other fragile items, at the store's fragile fill %. Null = not fragile.
  """
  fragile: Boolean
  """
  Ships alone in its own packaging (never in a shared box). Null = the category's setting applies.
  """
  ownPackaging: Boolean
  "The ID of the product."
  productId: ID!
}

"""
Changes to a product's delivery flags. A field left out keeps its saved value, and null clears it so own packaging follows the category.
"""
input ProductDeliveryFlagsInput {
  """True when the product is fragile."""
  fragile: Boolean
  """True when the product ships in its own packaging."""
  ownPackaging: Boolean
}

"""
AI-generated suggestions for a product. Suggestion-only: nothing is written to the catalog until the user approves and saves through the normal product update path.
"""
type ProductEnrichmentSuggestion {
  """Web-verified spec attributes for the default variant (may be empty)"""
  attributes: [EnrichmentAttribute!]!
  """
  Remaining balance, preformatted e.g. "USD 9.84"
  """
  balanceDisplay: String
  """Remaining AI credit balance, formatted dollars"""
  balanceDollars: String
  """The suggested brand."""
  brand: EnrichmentBrandSuggestion
  """Best-matching existing category, or null if none fit"""
  category: EnrichmentCategorySuggestion
  """
  Cost of this enrichment, preformatted e.g. "USD 0.08"
  """
  costDisplay: String
  """AI credits (cents) consumed by this enrichment"""
  creditsUsed: Float!
  """Customer-friendly description (plain text)"""
  description: String
  """Web-verified dimensions/weight, or null when none could be confirmed"""
  dimensions: EnrichmentDimensions
  """Validated public image candidates (may be empty when none were found)"""
  imageCandidates: [EnrichmentImageCandidate!]!
  """
  Human-readable notes, e.g. "No public image found"
  """
  notes: String
  """Inferred B2B search/discovery tags (may be inferred, not web-grounded)"""
  tags: [String!]!
  """Best-matching existing base unit of measure, or null if none fit"""
  unit: EnrichmentUnitSuggestion
}

"""Filters for the product list."""
input ProductFilterInput {
  """Only products below their reorder point."""
  belowReorderPoint: Boolean
  "The ID of the brand."
  brandId: ID
  "The ID of the category."
  categoryId: ID
  """Only products that are in stock."""
  inStock: Boolean
  """Only products priced at or below this."""
  priceMax: Float
  """Only products priced at or above this."""
  priceMin: Float
  "Text to search for."
  search: String
  """Only products in one of these statuses."""
  status: [ProductStatus!]
  """Only products with one of these tags."""
  tags: [String!]
  """
  Only products changed since this moment, including deleted ones so an offline client can drop its copies.
  """
  updatedAfter: DateTime
}

"""How many importable rows carry price tiers in one currency."""
type ProductImportCurrencyCount {
  "ISO 4217 currency code."
  currency: String!
  """True for the organization's base currency. A blank cell counts here."""
  isBase: Boolean!
  """How many rows."""
  rowCount: Int!
}

"""A product import and how far it has got."""
type ProductImportEntity {
  """How many chunks are done, so a stopped import can resume."""
  chunkCheckpoint: Int!
  """How many products would be created."""
  createCount: Int!
  "When the record was created."
  createdAt: DateTime!
  """How many rows have errors."""
  errorRows: Int!
  """Why the import failed, if it did."""
  failureReason: String
  """The name of the file."""
  filename: String!
  "The unique ID of this record."
  id: String!
  """Whether it only creates new products or updates existing ones too."""
  mode: ProductImportMode!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """How many rows have been staged."""
  stagedRows: Int!
  """Where the import stands."""
  status: ProductImportStatus!
  """How many chunks the import is processed in."""
  totalChunks: Int!
  """How many rows the file has."""
  totalRows: Int!
  """How many products would be updated."""
  updateCount: Int!
  "When the record was last changed."
  updatedAt: DateTime!
  """How many rows are valid."""
  validRows: Int!
  """How many rows have warnings."""
  warningRows: Int!
}

"""The file of rows that had errors."""
type ProductImportErrorFile {
  """The name of the file."""
  filename: String!
  """How many rows it holds."""
  rowCount: Int!
  """A short-lived download link. Empty when there are no error rows."""
  url: String
}

"""
How a product import treats existing products: CREATE_ONLY adds new ones only, UPSERT also updates existing ones.
"""
enum ProductImportMode {
  """Only new products are created; existing ones are left alone."""
  CREATE_ONLY
  """New products are created and existing ones are updated."""
  UPSERT
}

"""
A dry run of a product import: counts, samples, and the decisions made for the operator.
"""
type ProductImportPreview {
  """
  Decisions made for the operator while validating, one sentence each, such as unit spellings matched to the organization's own units.
  """
  autoAppliedRules: [String!]!
  """How many products would be created."""
  createCount: Int!
  """
  The currency the price tiers of importable rows will be saved in, base currency first. Empty when no row has price tiers.
  """
  currencySummary: [ProductImportCurrencyCount!]!
  """How many rows have errors."""
  errorRows: Int!
  """The ID of the import."""
  importId: String!
  """Whether it only creates new products or updates existing ones too."""
  mode: ProductImportMode!
  """A few rows with errors."""
  sampleErrors: [ProductImportSampleError!]!
  """A few valid rows, to show what the import will do."""
  sampleRows: [ProductImportSampleRow!]!
  """Where the import stands."""
  status: ProductImportStatus!
  """How many chunks the import is processed in."""
  totalChunks: Int!
  """How many rows the file has."""
  totalRows: Int!
  """How many products would be updated."""
  updateCount: Int!
  """How many rows are valid."""
  validRows: Int!
  """How many rows have warnings."""
  warningRows: Int!
}

"""What a rollback of an import undid."""
type ProductImportRollbackResult {
  """How many variants were deactivated instead of deleted."""
  deactivatedVariants: Int!
  """How many products were deleted."""
  deletedProducts: Int!
  """How many variants were deleted."""
  deletedVariants: Int!
  """
  Committed rows that updated an existing variant. Rollback does not revert updates (no pre-image is stored), so these SKUs keep the import's values.
  """
  notRevertedCount: Int!
}

"""A row with errors, shown in the preview."""
type ProductImportSampleError {
  """What was wrong with the row."""
  errors: [String!]!
  """The row number in the file."""
  rowNumber: Int!
  """The SKU on the row."""
  sku: String
}

"""A valid row, shown in the preview."""
type ProductImportSampleRow {
  """Whether the row would create or update a product."""
  action: String
  """The name of the product."""
  productName: String
  """The row number in the file."""
  rowNumber: Int!
  """The SKU on the row."""
  sku: String
}

"""
Where a product import stands: UPLOADED, MAPPING, VALIDATING, PREVIEW, COMMITTING, COMPLETED, FAILED or ROLLED_BACK.
"""
enum ProductImportStatus {
  """The rows are being saved."""
  COMMITTING
  """Finished."""
  COMPLETED
  """Stopped with an error."""
  FAILED
  """Waiting for the column mapping."""
  MAPPING
  """Ready to review before saving."""
  PREVIEW
  """Undone after saving."""
  ROLLED_BACK
  """The file is uploaded."""
  UPLOADED
  """The rows are being checked."""
  VALIDATING
}

"""The stock of a product in one warehouse."""
type ProductInventory {
  """The quantity free to allocate."""
  availableQuantity: Float!
  """The batch number of the stock."""
  batchNumber: String
  "When the record was created."
  createdAt: DateTime!
  """The date the stock expires."""
  expiryDate: DateTime
  "The unique ID of this record."
  id: ID!
  """The quantity on order and not yet received."""
  incomingQuantity: Float!
  """The highest quantity the row should hold."""
  maximumQuantity: Float
  """The lowest quantity the row should hold."""
  minimumQuantity: Float!
  "The ID of the product."
  productId: String!
  """The quantity on hand."""
  quantity: Float!
  """The quantity at which the row counts as low stock."""
  reorderPoint: Float!
  """How much to buy when the reorder point is reached."""
  reorderQuantity: Float!
  """The quantity held by confirmed orders."""
  reservedQuantity: Float!
  """The serial number of the stock."""
  serialNumber: String
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the product variant."
  variantId: String
  """The warehouse."""
  warehouse: Warehouse!
  "The ID of the warehouse."
  warehouseId: String!
}

"""The margin of one product."""
type ProductMargin {
  """The cost of what was sold."""
  cost: Float!
  """The margin as a percent of revenue."""
  marginPct: Float!
  """The name of the product."""
  name: String!
  "The ID of the product."
  productId: ID!
  """The revenue."""
  revenue: Float!
}

"""How one product sold."""
type ProductPerf {
  """The change against the previous period of the same length, in percent."""
  deltaPct: Float!
  """The name of the product."""
  name: String!
  """The revenue in the previous period of the same length."""
  previousRevenue: Float!
  "The ID of the product."
  productId: ID!
  """The revenue."""
  revenue: Float!
  """How many units were sold."""
  units: Float!
}

"""A suggested related product."""
type ProductRelationSuggestion {
  "The unique ID of this record."
  id: ID!
  """A note on why it is suggested."""
  note: String
  """The suggested product."""
  relatedProduct: SuggestedProduct!
  """How the product is related, for example upsell or cross-sell."""
  type: ProductRelationType!
}

"""
how a suggested product relates to the source product (UPSELL / CROSS_SELL / SUBSTITUTE).
"""
enum ProductRelationType {
  """A product bought together with this one."""
  CROSS_SELL
  """A product that can replace this one."""
  SUBSTITUTE
  """A higher-end product to offer instead."""
  UPSELL
}

"""
A return of goods, sales or purchase side, with its lines and the notes raised from it.
"""
type ProductReturn {
  """
  The total in the organization's base currency, frozen when the return was created. Use this to add up returns in different currencies.
  """
  baseTotalAmount: Float
  "When the record was created."
  createdAt: DateTime!
  """The credit notes raised from the return."""
  creditNotes: [ReturnCreditNote!]
  "ISO 4217 currency code."
  currency: String
  """The debit notes raised from the return."""
  debitNotes: [ReturnDebitNote!]
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who created the record."
  enteredBy: String!
  """The user who entered the return."""
  enterer: User
  """
  The rate frozen when the return was created: 1 unit of the return's currency in the organization's base currency.
  """
  exchangeRate: Float
  """The goods receipt the return is against, for a purchase return."""
  grn: GRN
  """
  The ID of the goods receipt the return is against, for a purchase return.
  """
  grnId: String
  "The unique ID of this record."
  id: ID!
  """The lines of the return."""
  items: [ProductReturnItem!]!
  """Notes about the return."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The ID of the order the goods came from."""
  originalOrderId: String!
  """The purchase order the goods came from, for a purchase return."""
  originalPurchaseOrder: PurchaseOrder
  """The sales order the goods came from, for a sales return."""
  originalSalesOrder: SalesOrder
  """The customer or vendor the goods go back to or come from."""
  partner: Partner
  "The ID of the partner."
  partnerId: String!
  """When the return was processed."""
  processedAt: DateTime
  """The ID of the user who processed the return."""
  processedBy: String
  """The user who processed the return."""
  processor: User
  """Why the goods are returned."""
  reason: ReturnReason!
  """Free-text detail on the reason."""
  reasonDescription: String
  """The date of the return."""
  returnDate: DateTime!
  """The return number, unique within the organization."""
  returnNumber: String!
  """Where the return stands in its lifecycle."""
  status: ReturnStatus!
  """The return amount before tax."""
  subtotal: Float!
  """The tax on the return."""
  taxAmount: Float!
  """The return total including tax, in the return's currency."""
  totalAmount: Float!
  """The kind of return."""
  type: ReturnType!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The warehouse that receives or sends the goods."""
  warehouse: Warehouse
  "The ID of the warehouse."
  warehouseId: String!
}

"""One line of a return."""
type ProductReturnItem {
  """The quantity accepted after inspection."""
  acceptedQuantity: Float!
  """The condition the item came back in."""
  condition: ItemCondition!
  "When the record was created."
  createdAt: DateTime!
  """Why rejected stock is disposed of."""
  disposalReason: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes about the line."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """
  The list price on the source line before discounts. unitPrice is the net price charged.
  """
  originalPrice: Float
  """The product returned."""
  product: Product
  "The ID of the product."
  productId: String!
  """The quantity returned."""
  quantity: Float!
  """The quantity rejected after inspection."""
  rejectedQuantity: Float!
  """True when accepted stock goes back into inventory."""
  restockable: Boolean!
  """The ID of the return the line belongs to."""
  returnId: String!
  """The line total."""
  totalAmount: Float!
  """The net price of one unit."""
  unitPrice: Float!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The product variant returned."""
  variant: ProductVariant
  "The ID of the product variant."
  variantId: String!
}

"""A column the product list can be sorted by."""
enum ProductSortField {
  """When the product was created."""
  CREATED_AT
  """The product name."""
  NAME
  """The price."""
  PRICE
  """The SKU."""
  SKU
  """When the product was last changed."""
  UPDATED_AT
}

"""How to sort the product list."""
input ProductSortInput {
  """The column to sort by."""
  field: ProductSortField!
  """The sort direction."""
  order: SortOrder!
}

"""The status of a product"""
enum ProductStatus {
  """For sale."""
  ACTIVE
  """No longer sold."""
  DISCONTINUED
  """Not for sale for now."""
  INACTIVE
}

"""Headline product figures."""
type ProductSummary {
  """How many are active."""
  activeProducts: Int!
  """How many are inactive."""
  inactiveProducts: Int!
  """When the figures were worked out."""
  lastUpdated: DateTime!
  """How many are low on stock."""
  lowStockProducts: Int!
  """How many are out of stock."""
  outOfStockProducts: Int!
  """How many products each category holds."""
  productsByCategory: [ProductsByCategory!]!
  """The most recently added products."""
  recentProducts: [Product!]!
  """The value of all stock."""
  totalInventoryValue: Float!
  """How many products there are."""
  totalProducts: Int!
}

"""How one product's sales are moving."""
type ProductTrend {
  """The growth, in percent."""
  growthRate: Float!
  "The ID of the product."
  productId: String!
  """The name of the product."""
  productName: String!
  """The direction: up, down or flat."""
  trend: String!
}

"""
A unit (pack) set up on a product or variant: its conversion factor to the base unit, the documents it can be used on, and its ordering and pricing rules.
"""
type ProductUOM {
  """Barcode of this pack."""
  barcode: String
  """How many base units one of this unit contains. The base unit is 1."""
  conversionFactor: Float!
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  """Global Trade Item Number (GTIN) of this pack."""
  gtin: String
  """Height of one of this unit."""
  height: Float
  "The unique ID of this record."
  id: ID!
  """Whether this is the product's base unit."""
  isBase: Boolean!
  """Whether stock is held in this unit."""
  isInventory: Boolean!
  """Whether the unit can be used on purchase documents."""
  isPurchase: Boolean!
  """
  Whether the unit can be used on sales documents. A variant can have at most 3 sellable units.
  """
  isSales: Boolean!
  """Length of one of this unit."""
  length: Float
  """List price of one of this unit."""
  listPrice: Float
  """Largest quantity of this unit that can be ordered."""
  maxOrderQty: Float
  """Smallest quantity of this unit that can be ordered."""
  minOrderQty: Float!
  """Quantities of this unit are ordered in multiples of this."""
  orderMultiple: Float!
  """The ID of the product the unit is set up on."""
  productId: String!
  """Sale price of one of this unit."""
  salePrice: Float
  """Standard cost of one of this unit."""
  standardCost: Float
  """The unit of measure."""
  uom: UnitOfMeasure!
  """The ID of the unit of measure."""
  uomId: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """
  The ID of the variant the unit is set up on. Empty for a product-wide unit.
  """
  variantId: String
  """Weight of one of this unit."""
  weight: Float
  """Width of one of this unit."""
  width: Float
}

"""A unit (pack) of a product with its list and sale price."""
type ProductUOMEntry {
  """The list price in this unit."""
  listPrice: Float
  """The sale price in this unit."""
  salePrice: Float
  """The unit of measure."""
  uom: UnitOfMeasure!
  "The ID of the unit of measure."
  uomId: ID!
  "The ID of the product variant."
  variantId: ID
}

"""
A unit (pack) of a product as the customer portal shows it: its conversion factor, prices and order limits.
"""
type ProductUOMType {
  """How many base units one of this unit holds."""
  conversionFactor: Float!
  """True when this is the base unit."""
  isBase: Boolean!
  """True when the product can be sold in this unit."""
  isSales: Boolean!
  """The list price in this unit."""
  listPrice: Float
  """The largest quantity as entered on the pack, in this pack's own units."""
  maxOrderQty: Float
  """
  The smallest quantity as entered on the pack, in this pack's own units.
  """
  minOrderQty: Float
  """Quantities step by this."""
  orderMultiple: Float!
  """The sale price in this unit."""
  salePrice: Float
  """The code of the unit of measure."""
  uomCode: String!
  "The ID of the unit of measure."
  uomId: ID!
  """The name of the unit of measure."""
  uomName: String!
}

"""
A sellable version of a product, with its own SKU, price, units of measure and stock.
"""
type ProductVariant {
  """The QR code of the variant."""
  QRCode: String
  """The variant's attributes, such as colour or size, as JSON."""
  attributes: JSON!
  """The barcode of the variant."""
  barcode: String
  """The base unit of measure."""
  baseUOM: UnitOfMeasure
  """The ID of the base unit of measure."""
  baseUOMId: ID
  """The cost of one unit."""
  cost: Float
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The size of one unit, as JSON."""
  dimensions: JSON
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """The URL of the main image."""
  imageUrl: String
  """The URLs of the images."""
  imageUrls: [String!]
  """The stock of the variant, one entry per warehouse."""
  inventory: [ProductInventory!]
  """The unit of measure stock is kept in."""
  inventoryUOM: UnitOfMeasure
  """The ID of the unit of measure stock is kept in."""
  inventoryUOMId: ID
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """True when the variant is low on stock."""
  isLowStock: Boolean!
  """True when the variant is out of stock."""
  isOutOfStock: Boolean!
  """The largest quantity that can be ordered."""
  maxOrderQuantity: Float
  """The page description for search engines."""
  metaDescription: String
  """The page title for search engines."""
  metaTitle: String
  """The smallest quantity that can be ordered."""
  minOrderQuantity: Float!
  """The name of the variant."""
  name: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The list price."""
  price: Float
  """The product the variant belongs to."""
  product: Product
  "The ID of the product."
  productId: ID!
  """The unit of measure used for purchases."""
  purchaseUOM: UnitOfMeasure
  """The ID of the unit of measure used for purchases."""
  purchaseUOMId: ID
  """Pre-negotiated sale price"""
  salePrice: Float
  """The unit of measure used for sales."""
  salesUOM: UnitOfMeasure
  """The ID of the unit of measure used for sales."""
  salesUOMId: ID
  """The serial number of the variant."""
  serialNo: String
  """The SKU of the variant."""
  sku: String!
  """Tags on the variant."""
  tags: [String!]!
  """The quantity free to allocate across all warehouses."""
  totalAvailable: Float!
  """The quantity held by confirmed orders across all warehouses."""
  totalReserved: Float!
  """The quantity on hand across all warehouses."""
  totalStock: Float!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """
  Qty-break price ladder. NOT populated by the products list projection — use productVariants(productId:) for variant detail.
  """
  variantPrices: [VariantPrice!]
  """The weight of one unit."""
  weight: Float
}

"""Variants to bulk delete."""
input ProductVariantBulkDeleteInput {
  """
  A unique key per confirm click. Sending the same key again returns the existing operation instead of deleting twice.
  """
  idempotencyKey: String
  """The IDs of the variants to delete."""
  variantIds: [ID!]!
}

"""How many variants a product has."""
type ProductVariantCount {
  """How many variants."""
  count: Int!
  "The ID of the product."
  productId: ID!
}

"""An active variant with no weight and/or no size of its own."""
type ProductVariantShippingDataGap {
  """The product's primary (else first) category."""
  categoryName: String
  """True when the variant has no size of its own."""
  missingSize: Boolean!
  """True when the variant has no weight of its own."""
  missingWeight: Boolean!
  "The ID of the product."
  productId: ID!
  """The name of the product."""
  productName: String!
  """The SKU of the variant."""
  sku: String!
  "The ID of the product variant."
  variantId: ID!
  """The name of the variant."""
  variantName: String
}

"""One page of variants with no weight or size."""
type ProductVariantShippingDataGapPage {
  """The variants on this page."""
  items: [ProductVariantShippingDataGap!]!
  """How many were skipped."""
  skip: Int!
  """How many were asked for."""
  take: Int!
  """How many variants match, over all pages."""
  total: Int!
}

"""How many products a category holds."""
type ProductsByCategory {
  """The category."""
  category: Category
  """How many products it holds."""
  count: Int!
}

"""
A change the copilot proposes, shown as a card for the user to approve.
"""
type ProposalCardType {
  """The ID of the batch the proposal was applied in."""
  batchId: String
  """When the card was made, in epoch milliseconds."""
  createdAt: Float!
  """The estimated credit cost, in cents."""
  creditEstimateCents: Int
  """Why the last apply failed. Empty for a card that has not failed."""
  error: String
  """A report of what applying it did."""
  executionReport: JSON
  "The unique ID of this record."
  id: ID!
  """What the proposal does."""
  kind: CopilotProposalKind!
  """The proposed change."""
  payload: JSON!
  """Why a person rejected the card."""
  rejectReason: String
  """Where the proposal stands."""
  status: CopilotProposalStatus!
  """The ID of the card that replaced this one."""
  supersededById: String
  """When the card last changed, in epoch milliseconds."""
  updatedAt: Float!
}

"""The branding anyone may read, without signing in."""
type PublicBrandingSettings {
  """The name of the company."""
  companyName: String!
  """The URL of the favicon."""
  faviconUrl: String!
  """The URL of the logo."""
  logoUrl: String!
  """The main brand colour."""
  primaryColor: String
}

"""
The portal settings returned to the customer portal and buyer app. It carries nothing sensitive.
"""
type PublicPortalConfig {
  """The accent colour."""
  accentColor: String!
  """True when customers can order directly."""
  allowDirectOrders: Boolean!
  """True when visitors can browse without signing in."""
  allowGuestBrowsing: Boolean!
  """True when customers can request quotes."""
  allowQuoteRequests: Boolean!
  """True when customers can register themselves."""
  allowSelfRegistration: Boolean!
  """True when customer orders go through the buyer-side approval workflow."""
  approvalWorkflowEnabled: Boolean!
  """
  True when the branch features of the portal are on: the branch toggle on addresses, the branch picker and branch-scoped approvals.
  """
  branchesEnabled: Boolean!
  """
  The one host the portal treats as its address for this organization: the verified primary custom domain when there is one, otherwise the subdomain.
  """
  canonicalHost: String!
  """
  The organization's country code, so a new customer address defaults to the seller's country.
  """
  countryCode: String
  "ISO 4217 currency code."
  currencyCode: String
  """
  Currency symbol display style: "local" | "international" | "code_only". Display-only; null when the org has never set it.
  """
  currencySymbolStyle: String
  """
  Org calendar date format, e.g. "DD-MM-YYYY". Display-only; null when the org has never set it.
  """
  dateFormat: String
  """The URL of the portal favicon."""
  faviconUrl: String
  """
  True when the organization has at least one enabled payment gateway whose keys are verified, so online payment can be offered.
  """
  gatewayEnabled: Boolean!
  """True when the portal is switched on."""
  isEnabled: Boolean!
  """The URL of the portal logo."""
  logoUrl: String
  """Android application id of this tenant's buyer-app binary."""
  mobileAndroidPackageName: String
  """SHA-256 certificate fingerprints Android accepts for this app."""
  mobileAndroidSha256CertFingerprints: [String!]
  """Play Store listing URL for this tenant's buyer app."""
  mobileAndroidStoreUrl: String
  """
  URL scheme of this tenant's buyer app (for example `myshop` for myshop:// links).
  """
  mobileAppScheme: String
  """Apple Developer Team ID for this tenant's buyer-app binary."""
  mobileAppleTeamId: String
  """iOS bundle identifier of this tenant's buyer-app binary."""
  mobileIosBundleId: String
  """App Store listing URL for this tenant's buyer app."""
  mobileIosStoreUrl: String
  """
  The image shown wherever a product, category or other catalog image is missing.
  """
  placeholderImageUrl: String
  """The name shown on the portal."""
  portalName: String!
  """
  The canonical host as an origin the buyer app can share a product link on, without a trailing slash.
  """
  portalOrigin: String
  """The main brand colour."""
  primaryColor: String!
  """How many days a quote stays valid."""
  quoteValidityDays: Int!
  """
  True when a buyer-created address starts inactive and a seller must activate it before the buyer can order to it.
  """
  requireAddressApproval: Boolean!
  """True when new customers must be approved before they can order."""
  requireCustomerApproval: Boolean!
  """How many days after delivery a return can be requested."""
  returnsWindowDays: Int!
  """True when stock levels are shown."""
  showInventory: Boolean!
  """True when prices are shown."""
  showPricing: Boolean!
  """The subdomain of the portal."""
  subdomain: String!
  """The support email address."""
  supportEmail: String
  """The support phone number."""
  supportPhone: String
  """The welcome message on the portal."""
  welcomeMessage: String
}

"""
The storefront page buyers see on the customer portal: the LIVE published theme (never the draft), or the basic default theme when the store has published nothing (owner ruling 2026-10-20).
"""
type PublicStorefrontPage {
  """
  Catalog records for every data section buyers on the web see in the part read: the page's own sections, or for CHROME the shared header's and footer's. One entry per placed section that lists records (keyed by sectionId).
  """
  catalog: [PublicStorefrontSectionCatalog!]!
  """
  The published document (a StorefrontDraft from @arc/theme-engine): the live version's, or the engine's fresh draft when nothing is published. Never the seller's unpublished draft.
  """
  document: JSON!
  """
  True when the store has published nothing and this is the basic default theme.
  """
  isDefault: Boolean!
  """The live version's number; null for the default theme."""
  liveVersion: Int
  """
  The id of the page read (the home page, the custom page, or the template the record uses). Null for CHROME, and for a custom page the store does not have.
  """
  pageId: String
}

"""
The live catalog records one placed section of the public storefront page lists.
"""
type PublicStorefrontSectionCatalog {
  """
  The section's records, as the theme editor's preview reads them: active records of this store only, ids, names and pictures, a product count only where the section asks for one. Empty when the section names no record the store has. Null when the catalog does not list that source in that mode (the section draws its not-loaded state).
  """
  records: [StorefrontCatalogRecord!]
  """The placed section's instance id in the document."""
  sectionId: String!
}

"""Purchasing figures for the period."""
type PurchaseAnalytics {
  """The average purchase order value."""
  averageOrderValue: Float!
  """Purchase orders split by status."""
  ordersByStatus: [OrderStatus!]!
  """The growth in orders against the previous period, in percent."""
  ordersGrowth: Float!
  """Purchases split by category."""
  purchasesByCategory: [CategoryPurchase!]!
  """Purchases over time."""
  purchasesByPeriod: [PeriodData!]!
  """The growth in purchases against the previous period, in percent."""
  purchasesGrowth: Float!
  """The products bought the most."""
  topProducts: [TopPurchaseProduct!]!
  """The suppliers bought from the most."""
  topSuppliers: [TopSupplier!]!
  """How many purchase orders there were."""
  totalOrders: Int!
  """The value purchased."""
  totalPurchases: Float!
}

"""A purchase order raised with a supplier."""
type PurchaseOrder {
  """
  Alternative tax rate applied to the order, when it differs from the per-line rates.
  """
  alternativeTaxRate: String
  """When the order was approved. Null until approved."""
  approvedAt: DateTime
  """The ID of the user who approved the order."""
  approvedBy: String
  """
  Total quantity cancelled across the lines when the unreceived balance was cancelled; 0 when none. Null when the lines were not loaded.
  """
  canceledQuantityTotal: Float
  """Cost tier the supplier prices were taken from."""
  costTier: String
  "When the record was created."
  createdAt: DateTime!
  """The ID of the user who created the order."""
  createdBy: String!
  """Display name of the user who created the order."""
  creatorName: String!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  """Address the supplier delivers to, as a JSON address object."""
  deliveryAddress: JSON
  """Free-text delivery instructions for the supplier."""
  deliveryInstructions: String
  """Order-level discount, in the order currency."""
  discountAmount: Float!
  """Estimated date the supplier ships the goods."""
  etd: DateTime
  """
  Exchange rate between the order currency and the organization's base currency.
  """
  exchangeRate: Float!
  """Date the goods are expected to arrive."""
  expectedDate: DateTime
  """Freight charge for the order, in the order currency."""
  freightAmount: Float!
  """
  When the last outstanding line was received. Null until the order is fully received.
  """
  fullyReceivedDate: DateTime
  "The unique ID of this record."
  id: ID!
  """Comments for your team only; never shown to the supplier."""
  internalComments: String
  """Date on the supplier's invoice."""
  invoiceDate: DateTime
  """Number of lines on the order."""
  itemCount: Int!
  """The lines on the order."""
  items: [PurchaseOrderItem!]!
  """
  Per order line: units already on returns made against this order, and units a new return may still take (received less returned). Creating a return refuses more.
  """
  lineReturns: [OrderLineReturns!]!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """
  The order total net of any quantity cancelled short, in the order currency. Equals totalAmount when nothing was cancelled, and is null when the lines were not loaded.
  """
  netTotalAmount: Float
  """Notes on the order, visible to the supplier."""
  notes: String
  """Currency code of the order's amounts."""
  orderCurrency: String!
  """Date the order was placed."""
  orderDate: DateTime!
  """The order's number, unique within your organization."""
  orderNumber: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """How much of the order has been paid."""
  paymentStatus: PaymentStatus!
  """Payment terms agreed with the supplier."""
  paymentTerms: String!
  """Project the purchase is for, if any."""
  projectName: String
  """The ID of the user who received the goods."""
  receivedBy: String
  """When goods were first received against the order."""
  receivedDate: DateTime
  """Display name of the user who received the goods."""
  receiverName: String
  """
  Address the order is shipped from or billed to, as a JSON address object.
  """
  shippingAddress: JSON
  """Shipping charge for the order, in the order currency."""
  shippingAmount: Float!
  """
  The sales order this PO supplies (number + status for the header chip). Only populated on the single-PO read.
  """
  sourceSalesOrder: LinkedSalesOrderRef
  """
  Id of the customer sales order this purchase order was raised to supply. Null for a stock-replenishment PO.
  """
  sourceSalesOrderId: String
  """Where the order is in its lifecycle."""
  status: PurchaseOrderStatus!
  """
  Sum of the line totals before order-level charges, in the order currency.
  """
  subtotal: Float!
  """When the supplier accepted the order."""
  supplierAcceptanceDate: DateTime
  """The supplier's code."""
  supplierCode: String
  """The supplier's display name."""
  supplierDisplayName: String
  """The supplier's email address."""
  supplierEmail: String
  "The ID of the supplier."
  supplierId: String!
  """Number on the supplier's invoice."""
  supplierInvoiceNo: String
  """The supplier's legal name."""
  supplierName: String
  """The supplier's phone number."""
  supplierPhone: String
  """Surcharge on the order, in the order currency."""
  surchargeAmount: Float!
  """Total tax on the order, in the order currency."""
  taxAmount: Float!
  """Grand total of the order, in the order currency."""
  totalAmount: Float!
  """Carrier tracking code for the shipment."""
  trackingCode: String
  "When the record was last changed."
  updatedAt: DateTime!
  """
  Optimistic-concurrency counter — pass back as expectedVersion on the next mutation.
  """
  version: Int!
  "The ID of the warehouse."
  warehouseId: String
}

"""A purchase order row that failed to import."""
type PurchaseOrderBulkImportError {
  """What was wrong with the row."""
  errors: [String!]!
  """The order number on that row, if given."""
  orderNumber: String
  """Row number in the import file, starting at 1."""
  row: Int!
}

"""Result of a bulk purchase order import."""
type PurchaseOrderBulkImportResult {
  """The failed rows and why."""
  errors: [PurchaseOrderBulkImportError!]!
  """Number of orders that failed."""
  failed: Int!
  """Number of orders imported."""
  success: Int!
}

"""A draft purchase order prepared from a sales order's lines."""
type PurchaseOrderDraftFromSalesOrder {
  """The draft lines."""
  lines: [PurchaseOrderDraftLine!]!
  """
  True when the lines' default suppliers differ — the buyer should split the order by supplier.
  """
  mixedSuppliers: Boolean!
  "The ID of the sales order."
  salesOrderId: ID!
  """Number of the sales order the draft comes from."""
  salesOrderNumber: String!
  """
  The default supplier when every line that has one agrees; null when no line has one or they disagree.
  """
  supplierId: String
}

"""A line of a draft purchase order."""
type PurchaseOrderDraftLine {
  "The ID of the product."
  productId: String!
  """Name of the product."""
  productName: String!
  """SKU of the product."""
  productSku: String!
  """
  Still to supply (ordered minus shipped), in `uomId` — the inventory unit, which a purchase order can always be denominated in.
  """
  quantity: Float!
  """
  This line's default (preferred) supplier, when the variant has one. Null otherwise.
  """
  supplierId: String
  "The ID of the unit of measure."
  uomId: String!
  """Name of the unit of measure."""
  uomName: String!
  "The ID of the product variant."
  variantId: String
  """Name of the product variant, if any."""
  variantName: String
}

"""Filters for listing purchase orders."""
input PurchaseOrderFiltersInput {
  """Only orders placed on or before this date."""
  endDate: DateTime
  """Only orders with this payment status."""
  paymentStatus: PaymentStatus
  "Text to search for."
  search: String
  """Field to sort by."""
  sortBy: PurchaseOrderSortField
  """Sort direction."""
  sortOrder: SortOrder
  """Only orders placed on or after this date."""
  startDate: DateTime
  """Only orders in these statuses."""
  status: [PurchaseOrderStatus!]
  "The ID of the supplier."
  supplierId: ID
}

"""A line on a purchase order."""
type PurchaseOrderItem {
  """Quantity cancelled before receipt."""
  canceledQuantity: Float!
  """
  Factor converting the line's unit of measure to the product's base unit.
  """
  conversionFactor: Float!
  "When the record was created."
  createdAt: DateTime!
  """Discount on this line, in the order currency."""
  discountAmount: Float!
  """Discount on this line, as a percentage."""
  discountPercent: Float!
  "The unique ID of this record."
  id: ID!
  """Factor converting the line's unit of measure to the stocking unit."""
  inventoryConversionFactor: Float!
  """The ID of the unit of measure the line is stocked in."""
  inventoryUOMId: String
  """Notes on this line."""
  notes: String
  "The ID of the product."
  productId: String!
  """Name of the product."""
  productName: String!
  """SKU of the product."""
  productSku: String!
  "The ID of the purchase order."
  purchaseOrderId: String!
  """Quantity ordered, in the line's unit of measure."""
  quantity: Float!
  """Quantity received so far."""
  receivedQuantity: Float!
  """Shipping charge allocated to this line."""
  shippingAmount: Float!
  """Surcharge allocated to this line."""
  surchargeAmount: Float!
  """Tax on this line, in the order currency."""
  taxAmount: Float!
  "The ID of the tax group."
  taxGroupId: String
  """Tax rate on this line, as a percentage."""
  taxRate: Float!
  """The IDs of the tax rates applied to this line."""
  taxRateIds: [String!]
  """Line total, in the order currency."""
  totalAmount: Float!
  """Price per unit, in the order currency."""
  unitPrice: Float!
  "The ID of the unit of measure."
  uomId: String!
  """Name of the unit of measure."""
  uomName: String!
  """Symbol of the unit of measure."""
  uomSymbol: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the product variant."
  variantId: String
  """Name of the product variant, if the product has variants."""
  variantName: String
}

"""A column the purchase order list can be sorted by."""
enum PurchaseOrderSortField {
  """The order date."""
  ORDER_DATE
  """The total amount."""
  TOTAL_AMOUNT
  """When the order was last changed."""
  UPDATED_AT
}

"""
Where a purchase order stands: DRAFT, SUBMITTED, APPROVED, PARTIALLY_RECEIVED, RECEIVED, CANCELLED or CLOSED.
"""
enum PurchaseOrderStatus {
  """Approved and ready to send."""
  APPROVED
  """Cancelled."""
  CANCELLED
  """Finished."""
  CLOSED
  """Being prepared."""
  DRAFT
  """Some goods have arrived."""
  PARTIALLY_RECEIVED
  """All goods have arrived."""
  RECEIVED
  """Sent for approval."""
  SUBMITTED
}

"""Counts and values across purchase orders, for the dashboard."""
type PurchaseOrderSummary {
  """Orders approved and not yet received."""
  approvedOrders: Int!
  """Orders still in draft."""
  draftOrders: Int!
  """When these figures were computed."""
  lastUpdated: DateTime!
  """Orders awaiting approval."""
  pendingOrders: Int!
  """Value of orders awaiting approval, in the base currency."""
  pendingValue: Float!
  """Orders fully received."""
  receivedOrders: Int!
  """Value of orders fully received, in the base currency."""
  receivedValue: Float!
  """The most recently updated orders."""
  recentOrders: [PurchaseOrder!]!
  """Number of purchase orders."""
  totalOrders: Int!
  """Total value of all orders, in the organization's base currency."""
  totalValue: Float!
}

"""One line of a purchase return."""
input PurchaseReturnItemInput {
  """The batch number of the returned stock."""
  batchNumber: String
  """The condition the item is in."""
  condition: String!
  """The defects found."""
  defects: [String!]
  "The ID of the product."
  productId: String!
  """The quantity returned. Must be greater than zero."""
  quantity: Int!
  "The ID of the product variant."
  variantId: String!
}

"""Purchase settings."""
input PurchaseSettingsInput {
  """The amount above which approval is needed."""
  approvalThreshold: String
  """The default payment terms."""
  defaultPaymentTerms: String
  """The ID of the default purchaser."""
  defaultPurchaser: String
  """The ID of the default receiving warehouse."""
  defaultReceivingWarehouse: String
  """The ID of the default supplier."""
  defaultSupplier: String
  """True to use goods receipts."""
  enableGRNProcess: Boolean
  """True to allow purchase returns."""
  enablePurchaseReturns: Boolean
  """True when purchases need approval."""
  requireApprovalForPurchases: Boolean
}

"""One push channel as the admin settings page shows it."""
type PushChannelControl {
  """The kinds of push an admin can turn off on this channel."""
  kinds: [String!]!
  """The rollout mode of the channel: off, shadow or on."""
  mode: String!
}

"""The push controls of both channels."""
type PushEventControls {
  """The buyer app channel."""
  buyer: PushChannelControl!
  """The staff app channel."""
  staff: PushChannelControl!
}

"""A quality check on returned goods."""
input QualityCheckInput {
  """Notes about the check."""
  notes: String
  """True when the goods passed the check."""
  passed: Boolean!
  """The quality score."""
  score: Float!
}

type Query {
  """
  Requires at least one of the permissions `settings:regional:read` or `settings:tenant:read`.
  
  Lists the timezones switched on for the organization. Requires permission to read regional or tenant settings.
  """
  activeTimezones: [Timezone!]!
  """
  Requires permission `audit:activity_log:read`.
  
  Returns one activity log entry: who did what to which record, when and from which source. Fails if the entry does not exist. Requires permission to read the activity log.
  """
  activityLog(
    """The ID of the activity log entry."""
    id: String!
  ): ActivityLogEntry!
  """
  Requires permission `audit:activity_log:read`.
  
  Returns activity log totals for the organization: events today, active users, and counts by action, record type and user, optionally for a filtered set. Requires permission to read the activity log.
  """
  activityLogAnalytics(
    """Optional filters. The same ones as activityLogs."""
    filter: ActivityLogFilterInput
  ): ActivityLogAnalytics!
  """
  Requires permission `audit:activity_log:read`.
  
  Lists the actions and record types the activity log records, for filtering it. Requires permission to read the activity log.
  """
  activityLogFacets: ActivityLogFacets!
  """
  Requires permission `audit:activity_log:read`.
  
  Lists the organization's activity log, one page at a time, optionally filtered by person, record type, action, source and dates. Pages hold at most 100 entries. Some courier cost details are shown only to viewers who may ship sales orders. Requires permission to read the activity log.
  """
  activityLogs(
    """
    Optional filters: search text, person, record type, action, source and a date range.
    """
    filter: ActivityLogFilterInput
    """The page number, starting at 1."""
    page: Int = 1
    """How many entries per page. Defaults to 25 and is capped at 100."""
    pageSize: Int = 25
  ): ActivityLogsResponse!
  """
  Requires a tenant administrator.
  
  Returns the administrator's overview of the organization: system overview, user activity, system health, security metrics, module usage, integrations and notifications. Only admins and owners can read it.
  """
  adminDashboard: AdminDashboard!
  """
  Requires at least one of the permissions `billing:ai_credit:read`, `catalog:copilot:chat` or `products:product:update`.
  
  The org's remaining AI credit balance (USD), for the enrichment UI. Needs the AI credit read, products update or copilot chat permission.
  """
  aiCreditBalance: AiCreditBalanceInfo!
  """
  Requires permission `billing:ai_credit:read`.
  
  The fixed set of USD top-up amounts the wallet UI offers.
  """
  aiCreditTopUpOptions: [AiCreditTopUpOption!]!
  """
  Requires permission `billing:ai_credit:read`.
  
  Wallet ledger entries (purchases, usage debits, reservation holds/settles/releases).
  """
  aiCreditTransactionHistory(
    "Maximum number of records to return."
    limit: Int
  ): [AiCreditTransactionEntry!]!
  """
  Requires permission `billing:ai_credit:read`.
  
  Recent AI usage (model calls metered against the wallet), most recent first.
  """
  aiCreditUsageHistory(
    """Only usage for this AI feature."""
    feature: String
    "Maximum number of records to return."
    limit: Int
    """Only usage for this AI model."""
    model: String
    "Number of records to skip before the first one returned."
    offset: Int
  ): [AiUsageLogEntry!]!
  """
  Requires permission `billing:ai_credit:read`.
  
  Windowed spend aggregate for the wallet page's KPI strip and burn sparkline.
  """
  aiCreditUsageSummary(
    """How many past days to include. Omit for the default window."""
    windowDays: Int
  ): AiCreditUsageSummary!
  """
  Requires permission `billing:ai_credit:read`.
  
  The org's AI-credit wallet balance for the settings page.
  """
  aiCreditWalletBalance: AiCreditWalletBalance!
  """
  Requires permission `users:user:read`.
  
  Get all user relationships in the organization
  """
  allUserRelationships: [UserRelationship!]!
  """
  Requires at least one of the permissions `settings:api:read` or `settings:tenant:read`.
  
  Get details of a specific API key
  """
  apiKey(
    """The ID of the API key."""
    id: String!
  ): ApiKeyResult
  """
  Requires at least one of the permissions `settings:api:read` or `settings:tenant:read`.
  
  List all API keys for your organization
  """
  apiKeys: [ApiKeyResult!]!
  """
  Requires permission `analytics:sales:read`.
  
  App activity analytics: how customers use the buyer app and the web portal, over a date range. Every number is limited to the customers you may see. Needs the sales analytics read permission.
  """
  appActivityAnalytics(
    """Optional settings for the report."""
    options: AppActivityOptionsInput
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): AppActivityAnalytics!
  """
  Requires permission `analytics:sales:read`.
  
  App activity for one customer over a date range, for the customer drawer. A customer outside your book is refused with the same not-found a missing one gets. Needs the sales analytics read permission.
  """
  appActivityCustomer(
    """The ID of the customer."""
    partnerId: ID!
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): AppActivityCustomerDetail!
  """
  Requires permission `analytics:sales:read`.
  
  The customers or products behind one app activity number, one page at a time, over a date range. Needs the sales analytics read permission.
  """
  appActivityDrilldown(
    """Which number to drill into, plus paging."""
    input: AppActivityDrilldownInput!
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): AppActivityDrilldownPage!
  """
  Requires permission `analytics:sales:read`.
  
  App activity of guest visitors on the customer portal, meaning people who are not logged in, over a date range. Needs the sales analytics read permission.
  """
  appActivityGuests(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): AppActivityGuests!
  """
  Requires a tenant administrator.
  
  Lists customers that can be assigned to a given sales rep, one page at a time, never including customers that rep already owns. Backs the Assign customers picker on a user. Tenant admins only.
  """
  assignableCustomers(
    """The target sales rep and the search and paging options for the list."""
    input: AssignableCustomersInput!
  ): AssignableCustomersPage!
  """
  Public: no authentication required.
  
  Get list of all available currencies
  """
  availableCurrencies: [CurrencyListItem!]!
  """
  Requires permission `dashboard:main:read`.
  
  B2B dashboard figures for a date range. Both the start and end dates are required. Needs the dashboard read permission.
  """
  b2bDashboard(
    """The start and end dates. Both are required."""
    dateRange: DateRangeInput!
  ): B2BDashboard!
  """
  Requires permission `payments:bank-account:read`.
  
  Returns one bank account, with the account number masked. Fails if the account does not exist. Needs the bank accounts read permission.
  """
  bankAccount(
    """The ID of the bank account."""
    id: ID!
  ): BankAccount!
  """
  Requires at least one of the permissions `payments:bank-account:list`, `payments:bank-account:read`, `payments:collection:create`, `payments:payment:create` or `purchase:payment:create`.
  
  Lists the organization's bank accounts, with the account number masked. Filter by active status, account type, currency or search text. Needs the bank accounts read or list permission, or a permission to record a collection or a payment into one.
  """
  bankAccounts(
    """
    Optional filters: active status, account type, currency and search text.
    """
    filter: BankAccountFilter
  ): [BankAccount!]!
  """
  Requires an authenticated session.
  
  Get base currency for current organization
  """
  baseCurrency: BaseCurrencyInfo
  """
  Requires an authenticated session.
  
  Check if base currency is locked
  """
  baseCurrencyLockStatus: BaseCurrencyLockStatus!
  """
  Requires permission `sales:sales_order:ship`.
  
  Lists the enabled delivery partners that staff can book a shipment with, without secrets or settings, for the ship dialog and the return pickup picker. Needs the delivery partners plan feature and permission to ship sales orders.
  """
  bookableDeliveryPartners: [BookableDeliveryPartnerGql!]!
  """
  Requires at least one of the permissions `products:brand:read` or `products:product:read`.
  
  Returns one brand of your organization with its products. Fails if the brand does not exist. Needs the brands read or the products read permission.
  """
  brand(
    """The ID of the brand."""
    id: ID!
  ): Brand!
  """
  Requires permission `products:brand:read`.
  
  Returns brand counts for your organization: total, active, inactive and brands that have products, plus the five most recently created brands. Needs the brands read permission.
  """
  brandSummary(
    """
    Optional filters. Only the creation date range is used; the counts and the recent brands are limited to brands created in it.
    """
    filter: BrandFilterInput
  ): BrandSummary!
  """
  Requires at least one of the permissions `products:brand:list`, `products:brand:read`, `products:product:create`, `products:product:read`, `products:product:update` or `storefront:storefront:update`.
  
  Lists the brands of your organization with the number of products on each. Only active brands are returned unless the filter asks for another status. Needs the brands read or list permission, a products read, create or update permission, or the storefront update permission.
  """
  brands(
    """
    Optional filters: search text, status, creation date range, paging and sort order.
    """
    filter: BrandFilterInput
  ): BrandListResponse!
  """
  Requires permission `products:import:preview`.
  
  Parses a base64 CSV with a named mapping profile and returns a dry-run preview. Writes nothing.
  """
  bulkImportProductsGeneric(
    """The details of the bulk import products generic request."""
    input: BulkImportProductsGenericInput!
  ): GenericProductImportPreview!
  """
  Requires at least one of the permissions `payments:invoice:create`, `products:discount:read`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:quote:create`, `sales:quote:update`, `sales:sales_invoice:create`, `sales:sales_order:create` or `sales:sales_order:update`.
  
  Works out the discount on an amount for a customer, product, variant or category, and saves nothing. The result carries the original price, the discount, the final price, the percentage and the schemes applied. Needs the discounts read permission, or permission to create or edit a quote, sales order, invoice or purchase order.
  """
  calculateDiscount(
    """
    The base amount and quantity, and optionally the product, variant, category, customer, currency and region to match schemes against.
    """
    data: CalculateDiscountDto!
  ): CalculateDiscountResult!
  """
  Requires permission `products:pricing:read`.
  
  Returns the unit price of a variant for a quantity, taken from the best matching quantity tier in the base currency, or from the variant's base price when no tier matches. The result also carries the original price and the discount against it. Needs the pricing read permission.
  """
  calculateVariantPrice(
    """
    The customer tier to price for. When given, only tiers that list this customer tier apply.
    """
    customerTier: String
    """
    The quantity to price. Tiers apply by their minimum and maximum quantity.
    """
    quantity: Int!
    """The ID of the variant."""
    variantId: ID!
  ): CalculatedPrice!
  """
  Requires permission `catalog:copilot:chat`.
  
  Returns one catalog batch that the copilot applied. Fails if the batch does not exist. A batch whose run stopped without finishing is recovered first. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  catalogBatch(
    """The ID of the catalog batch."""
    id: ID!
  ): CatalogBatchType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Lists the catalog batches the copilot applied, most recently applied first, 20 by default. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  catalogBatches(
    """Optional: how many batches to return. Defaults to 20."""
    input: CatalogBatchesInput
  ): [CatalogBatchType!]!
  """
  Requires an authenticated session.
  
  Catalog performance analytics over a date range. Org-wide figures: needs the analytics:organization:read permission, so users limited to their own records are refused.
  """
  catalogPerformanceAnalytics(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): CatalogPerformanceAnalytics!
  """
  Requires permission `categories:category:list`.
  
  Lists the categories of your organization with their subcategories and product counts. Narrow the list by search text, parent, status or level. Requires permission to list categories.
  """
  categories(
    """
    Optional filters: search text, parent category, active status, level, or root categories only.
    """
    filters: CategoryFiltersInput
  ): [Category!]!
  """
  Requires permission `categories:category:read`.
  
  Returns one category with its parent, subcategories and product counts. Fails if the category does not exist. Requires permission to read categories.
  """
  category(
    """The ID of the category."""
    id: String!
  ): Category!
  """
  Requires permission `categories:category:list`.
  
  Returns one page of the direct subcategories of a category, or of the top-level categories when no parent is given. Pages are ordered by sort order, then name, and carry a total count for the same filters. Requires permission to list categories.
  """
  categoryChildren(
    """
    The cursor from the previous page's nextCursor. Omit it for the first page.
    """
    cursor: String
    """
    Only return active subcategories (true) or inactive ones (false). Omit it to return every status.
    """
    isActive: Boolean
    """
    How many subcategories to return per page, from 1 to 100. Defaults to 50.
    """
    limit: Int = 50
    """
    The ID of the category whose direct subcategories to list. Omit it to list top-level categories.
    """
    parentId: ID
    """
    Only return subcategories whose name contains this text, ignoring case.
    """
    search: String
  ): CategoryChildrenConnection!
  """
  Requires permission `categories:category:read`.
  
  Returns a category's own delivery defaults and what applies to the items in it. Requires permission to read categories.
  """
  categoryDeliveryDefaults(
    """The ID of the category."""
    categoryId: ID!
  ): CategoryDeliveryDefaults!
  """
  Requires permission `categories:category:list`.
  
  Returns category statistics for your organization: counts of total, active, inactive, root, parent and child categories and those with or without active products, the tree depth, recent and most used categories, and the category tree. Requires permission to list categories.
  """
  categorySummary: CategorySummary!
  """
  Requires an authenticated session.
  
  Returns one team chat channel with its members and creator. A channel of another organization, or one the caller cannot access, is refused. Needs a signed-in user.
  """
  chatChannel(
    """The ID of the chat channel."""
    id: String!
  ): ChatChannel!
  """
  Requires an authenticated session.
  
  Lists the team chat channels the caller can see, with their members. Needs a signed-in user.
  """
  chatChannels: [ChatChannel!]!
  """
  Requires an authenticated session.
  
  Returns one conversation: its title, type, message count and last message time. It is available to the conversation's owner, to members of its channel, and in the default channel. A conversation of another organization reads as missing. Needs a signed-in user.
  """
  chatConversation(
    """The ID of the conversation."""
    id: String!
  ): ChatConversation!
  """
  Requires an authenticated session.
  
  Lists the caller's team chat conversations, including those in channels they belong to and the default channel. Needs a signed-in user.
  """
  chatConversations: [ChatConversation!]!
  """
  Requires an authenticated session.
  
  Lists the messages in one conversation, oldest first, with sender, text and time. The caller must have access to the conversation. Needs a signed-in user.
  """
  chatMessages(
    """The ID of the conversation."""
    conversationId: String!
  ): [ChatMessage!]!
  """
  Requires at least one of the permissions `storefront:storefront:read` or `storefront:storefront:update`.
  
  Read-only list of the organization's retired Home CMS blocks, ordered by position — the source of the theme editor's Home CMS importer. The Home CMS editor is retired. Needs the storefront read or update permission.
  """
  cmsBlocks(
    """Only blocks of this kind of home section."""
    kind: HomeSectionKind
  ): [CmsBlock!]!
  """
  Requires permission `commissions:commission:read`.
  
  Lists who earns commission, one page at a time, with each beneficiary's total, pending, locked and paid amounts over the whole filtered set. Use commissionBeneficiariesCount for the total. Requires permission to read commissions.
  """
  commissionBeneficiaries(
    """Optional filters, the same as commissions."""
    filters: CommissionFiltersInput
    """How many beneficiaries to skip."""
    skip: Int
    """How many beneficiaries to return."""
    take: Int
  ): [CommissionBeneficiary!]!
  """
  Requires permission `commissions:commission:read`.
  
  Returns how many distinct beneficiaries match the filter, for the pager of commissionBeneficiaries. Requires permission to read commissions.
  """
  commissionBeneficiariesCount(
    """Optional filters. The same ones as commissionBeneficiaries."""
    filters: CommissionFiltersInput
  ): Int!
  """
  Requires permission `commissions:commission:read`.
  
  Lists the organization structure for the commission setup: one row per active staff user, with their role, level, rate and who they report to. Requires permission to read commissions.
  """
  commissionHierarchy: [CommissionHierarchyRow!]!
  """
  Requires permission `commissions:commission:read`.
  
  Returns commission ledger totals by status over the whole filtered set, with entry and order counts and the roles that still have no rate. Requires permission to read commissions.
  """
  commissionLedgerSummary(
    """Optional filters. The same ones as commissions."""
    filters: CommissionFiltersInput
  ): CommissionLedgerSummary!
  """
  Requires permission `commissions:commission:read`.
  
  The commission ledger's by-order view: a page of orders, each with the commission rows of its chain. It takes the same filters as commissions; send skip and take to page, and use commissionOrderGroupsCount for the total. Needs the commission read permission.
  """
  commissionOrderGroups(
    """Optional filters, the same as commissions."""
    filters: CommissionFiltersInput
    """Number of orders to skip. Send with take for paging."""
    skip: Int
    """Number of orders to return."""
    take: Int
  ): [CommissionOrderGroup!]!
  """
  Requires permission `commissions:commission:read`.
  
  The number of distinct orders in the filtered commission ledger: the pager total for commissionOrderGroups.
  """
  commissionOrderGroupsCount(
    """The same filters as commissionOrderGroups."""
    filters: CommissionFiltersInput
  ): Int!
  """
  Requires permission `commissions:commission:read`.
  
  Lists commission payouts made to sales reps, optionally for one person or period. Send skip and take to page, and use commissionPayoutsCount for the total. Requires permission to read commissions.
  """
  commissionPayouts(
    """The commission period, as YYYY-MM. Omit it for every period."""
    period: String
    """
    How many payouts to skip. Omit skip and take to return the whole scoped list.
    """
    skip: Int
    """How many payouts to return."""
    take: Int
    """The ID of the sales rep."""
    userId: String
  ): [CommissionPayout!]!
  """
  Requires permission `commissions:commission:read`.
  
  Returns how many commission payouts match the same person and period as commissionPayouts, ignoring paging, for a pager. Requires permission to read commissions.
  """
  commissionPayoutsCount(
    """The commission period, as YYYY-MM. Omit it for every period."""
    period: String
    """The ID of the sales rep."""
    userId: String
  ): Int!
  """
  Requires permission `commissions:commission:read`.
  
  Lists the commission rate set for each role. Requires permission to read commissions.
  """
  commissionRoleRates: [CommissionRoleRate!]!
  """
  Requires permission `commissions:commission:read`.
  
  Lists commission entries earned on sales, optionally filtered, for the whole organization or only the caller's scope. Send skip and take to page, and use commissionsCount for the total. Requires permission to read commissions.
  """
  commissions(
    """Optional filters: person, period, status and sort order."""
    filters: CommissionFiltersInput
    """
    How many entries to skip. Omit skip and take to return the whole scoped list.
    """
    skip: Int
    """How many entries to return."""
    take: Int
  ): [Commission!]!
  """
  Requires permission `commissions:commission:read`.
  
  Returns how many commission entries match the same filters and scope as commissions, ignoring paging, for a pager. Requires permission to read commissions.
  """
  commissionsCount(
    """Optional filters. The same ones as commissions."""
    filters: CommissionFiltersInput
  ): Int!
  """
  Requires at least one of the permissions `customers:customer:create` or `customers:customer:update`.
  
  Checks whether the given emails or mobile numbers already belong to another person, on this customer or another, so a contact form can warn before saving. A restricted rep never learns which out-of-scope customer holds a value. Needs the customers create or update permission.
  """
  contactIdentityConflicts(
    """The emails and mobile numbers to check."""
    input: ContactIdentityCheckInput!
  ): [ContactIdentityConflictInfo!]!
  """
  Requires permission `settings:controls:manage`.
  
  Returns one control, or null when the organization has none with that ID. Requires settings:controls:manage.
  """
  control(
    """The ID of the control."""
    id: ID!
  ): ControlRuleType
  """
  Requires permission `settings:controls:manage`.
  
  Who could approve requests needing each approval permission, and setup warnings (a payment-gated control with nothing verifying payments; a permission only one person holds). Only approval permissions are accepted. Requires settings:controls:manage.
  """
  controlApprovalCoverage(
    """
    Count you among the approvers. Off by default: the setup check asks who other than you could approve.
    """
    includeMe: Boolean! = false
    """Approval permissions to check, such as approvals:large_orders:approve."""
    permissions: [String!]!
  ): ControlApprovalCoverageType!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:delegation:manage`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve` or `purchase:purchase_order:approve`.
  
  Approval covers, newest start first (up to 200): MINE lists the ones you gave or were given, ALL every cover (needs approvals:delegation:manage).
  """
  controlApprovalDelegations(
    """MINE (default) or ALL."""
    scope: ControlApprovalDelegationScope! = MINE
  ): [ControlApprovalDelegation!]!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve`, `inventory:stock_adjustment:create`, `payments:collection:create`, `payments:collection:update`, `payments:payment:allocate`, `payments:payment:create`, `payments:payment:update`, `purchase:grn:create`, `purchase:grn:update`, `purchase:payment:allocate`, `purchase:payment:create`, `purchase:payment:update`, `purchase:purchase_invoice:create`, `purchase:purchase_invoice:update`, `purchase:purchase_order:approve`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:credit_note:create`, `sales:sales_order:confirm`, `sales:sales_order:deliver`, `sales:sales_order:ship`, `sales:sales_order:update`, `sales:shipment:create`, `sales:shipment:update` or `settings:controls:manage`.
  
  One approval request with its signatures, what you may do with it, and the values its control saw when it was raised.
  """
  controlApprovalRequest(
    """The approval request's ID."""
    id: ID!
  ): ControlApprovalRequest!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve`, `inventory:stock_adjustment:create`, `payments:collection:create`, `payments:collection:update`, `payments:payment:allocate`, `payments:payment:create`, `payments:payment:update`, `purchase:grn:create`, `purchase:grn:update`, `purchase:payment:allocate`, `purchase:payment:create`, `purchase:payment:update`, `purchase:purchase_invoice:create`, `purchase:purchase_invoice:update`, `purchase:purchase_order:approve`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:credit_note:create`, `sales:sales_order:confirm`, `sales:sales_order:deliver`, `sales:sales_order:ship`, `sales:sales_order:update`, `sales:shipment:create`, `sales:shipment:update` or `settings:controls:manage`.
  
  Your approvals inbox, newest first: TO_DECIDE lists pending requests you may decide now, RAISED_BY_ME the ones you raised, ALL every request (needs settings:controls:manage). Each request says whether you may decide, recall or apply it.
  """
  controlApprovalRequests(
    """Which box, states and page."""
    filter: ControlApprovalRequestsFilter!
  ): ControlApprovalRequestConnection!
  """
  Requires permission `settings:controls:manage`.
  
  Lists the ready-made controls an admin can start from. Saving one creates an ordinary control. Requires settings:controls:manage.
  """
  controlPresets: [ControlPresetType!]!
  """
  Requires permission `settings:controls:manage`.
  
  Checks a control without saving it: the rule against the fact catalogue, its warehouse and customer references, and whether anyone other than you could approve it. Requires settings:controls:manage.
  """
  controlSetupCheck(
    """The control to check."""
    input: SaveControlInput!
  ): ControlSetupCheckType!
  """
  Requires permission `settings:controls:manage`.
  
  Returns every saved version of a control, newest first. Requires settings:controls:manage.
  """
  controlVersions(
    """The ID of the control."""
    id: ID!
  ): [ControlVersionType!]!
  """
  Requires permission `settings:controls:manage`.
  
  Lists the organization's controls with their decisions over the last 30 days. A control whose stored rule no longer validates is listed with invalid set. Requires settings:controls:manage.
  """
  controls(
    """Include archived controls."""
    includeArchived: Boolean! = false
  ): [ControlRuleType!]!
  """
  Requires permission `settings:controls:manage`.
  
  Returns the organization's controls kill switch: whether every control only observes, and who set it and why. Requires settings:controls:manage.
  """
  controlsKillSwitch: ControlsKillSwitchType!
  """
  Requires an authenticated session.
  
  Convert a quantity from one unit to another. Both units must be in the same category. Send productId to use that product's own pack conversions when it has them. Converting a unit to itself returns the quantity unchanged.
  """
  convertQuantity(
    """The quantity and the units to convert between."""
    data: ConvertQuantityInput!
  ): ConvertQuantityResult!
  """
  Requires permission `catalog:copilot:chat`.
  
  The CALLER'S standing approval rules for low-tier cards: the session rule for `sessionId` when given, and their own auto mode.
  """
  copilotApprovalRules(
    """Only the rule for this Copilot session. Omit to list all rules."""
    sessionId: ID
  ): CopilotApprovalRulesType!
  """
  Requires permission `catalog:copilot:chat`.
  
  How much this organization lets Minori do on a seller's behalf: `full` (anything their own permissions allow), `no_money` (drafting and catalog work, but nothing that moves money or stock), or `read_only` (answers questions, proposes nothing). It is a CAP — it can only ever narrow what a user's permissions already allow, never widen it.
  """
  copilotAutonomyLevel: CopilotAutonomyCapType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Poll a parse/apply/images job.
  """
  copilotJob(
    """The ID of the Copilot job."""
    jobId: ID!
  ): CopilotJob!
  """
  Requires permission `catalog:copilot:chat`.
  
  Whether Minori may remember facts for the caller, and where that setting comes from.
  """
  copilotMemoryEnabled: CopilotMemorySwitchType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Facts Minori has saved about the CALLER (subjectType USER, the default) or about the organization (TENANT, which additionally requires settings:organization:read). Newest first.
  """
  copilotMemoryFacts(
    """Only facts about this kind of subject."""
    subjectType: CopilotMemorySubjectType
  ): [CopilotMemoryFactType!]!
  """
  Requires permission `catalog:copilot:chat`.
  
  The account-enabled, priced OpenRouter models — cheapest first. The default picker choice is isCheapest.
  """
  copilotModels: [CopilotModelInfo!]!
  """
  Requires permission `catalog:copilot:chat`.
  
  This organization's saved Minori prompts. Each `body` is inserted as the seller's own message — it never reaches the system prompt, carries no skill, and gets exactly the permissions and autonomy cap the seller already has.
  """
  copilotPromptTemplates: [CopilotPromptTemplateType!]!
  """
  Requires permission `catalog:copilot:chat`.
  
  The caller's own scheduled copilot jobs. Org + user scoped.
  """
  copilotScheduledJobs: [CopilotScheduledJobType!]!
  """
  Requires permission `catalog:copilot:chat`.
  
  Load one of the CALLER'S OWN copilot threads. Org + user scoped (r1) — a colleague's thread, and any cross-tenant id, read as not-found.
  """
  copilotSession(
    """The ID of the Copilot session."""
    id: ID!
  ): CopilotSession!
  """
  Requires permission `catalog:copilot:chat`.
  
  The caller's OWN chat history, one page at a time: pinned first, then most recent. `search` matches titles and message text; `status: ARCHIVED` is the archived view. Org + user scoped.
  """
  copilotSessionHistory(
    """Cursor from the previous page's last item. Omit for the first page."""
    after: String
    """
    True: only chats holding a proposal card that still waits for your decision — including cards a connected app (MCP) proposed.
    """
    awaitingApproval: Boolean
    """The number of items to return."""
    first: Int = 20
    "Text to search for."
    search: String
    """ACTIVE (default) or ARCHIVED."""
    status: String
  ): CopilotSessionHistoryPage!
  """
  Requires permission `catalog:copilot:chat`.
  
  Messages of one of the caller's OWN chats that are older than `before`, oldest first. `copilotSession` returns only the newest window; this reads the rest.
  """
  copilotSessionMessages(
    """Return only messages older than this message ID."""
    before: ID!
    """The number of items to return."""
    first: Int = 20
    """The ID of the Copilot session."""
    sessionId: ID!
  ): CopilotMessagePage!
  """
  Requires permission `catalog:copilot:chat`.
  
  The caller's OWN copilot threads, most recent first. Org + user scoped — a user never lists a colleague's conversations.
  """
  copilotSessions(
    """Cursor from the previous page's last item. Omit for the first page."""
    after: String
    """The number of items to return."""
    first: Int = 20
  ): [CopilotSessionSummary!]!
  """
  Requires permission `settings:organization:read`.
  
  How many Minori turns each of this organization's buyers may start per UTC day, where the value comes from, the recommended value and the allowed range, and whether the plan grants buyers Minori at all.
  """
  copilotShopperDailyTurns: CopilotShopperTurnCapType!
  """
  Requires permission `catalog:copilot:chat`.
  
  Lists the organization's saved supplier import rules, one per supplier, that the copilot applies when it reads a supplier's file. Needs the catalog copilot feature on the plan and permission to chat with the copilot.
  """
  copilotSupplierRules: [SupplierRuleType!]!
  """
  Public: no authentication required.
  
  Get list of all available countries
  """
  countries: [CountryListItem!]!
  """
  Public: no authentication required.
  
  Get default settings for a country
  """
  countryDefaults(
    """The two-letter ISO country code."""
    countryCode: String!
  ): CountryDefaults
  """
  Requires at least one of the permissions `customers:customer:read`, `purchase:purchase_order:read`, `sales:sales_order:read` or `suppliers:supplier:read`.
  
  Read-only credit exposure for one partner. Use side SALES for a customer's receivables or PURCHASE for a supplier's payables; any other value reads as SALES. SALES needs the customer read or sales order read permission and the customer must be in your scope; PURCHASE needs the supplier read or purchase order read permission.
  """
  creditExposure(
    """The ID of the partner."""
    partnerId: ID!
    """
    SALES (customer receivables) or PURCHASE (supplier payables). Defaults to SALES.
    """
    side: String
  ): CreditExposureResult!
  """
  Requires permission `sales:credit_note:read`.
  
  Returns one credit note by ID. A user restricted to their own customers cannot open a note outside that book.
  """
  creditNote(
    """The ID of the credit note."""
    id: ID!
  ): CreditNote!
  """
  Requires permission `sales:credit_note:read`.
  
  Lists the audit trail of one credit note: who changed it, when, and what changed.
  """
  creditNoteAuditLogs(
    """The ID of the credit note."""
    creditNoteId: ID!
  ): [AuditLog!]!
  """
  Requires permission `sales:credit_note:list`.
  
  Returns summary figures for credit notes, such as counts by status.
  """
  creditNoteSummary: CreditNoteSummary!
  """
  Requires permission `sales:credit_note:list`.
  
  Lists credit notes with optional filters and `skip` / `take` paging.
  """
  creditNotes(
    """Filter criteria for credit note records. Omit to match all."""
    filters: CreditNoteFiltersInput
    "Number of records to skip. Send with take to page through results."
    skip: Int
    "Number of records to return."
    take: Int
  ): [CreditNote!]!
  """
  Requires permission `sales:credit_note:list`.
  
  Returns how many credit notes match the filters, without loading them.
  """
  creditNotesCount(
    """Filter criteria for credit note records. Omit to match all."""
    filters: CreditNoteFiltersInput
  ): Int!
  """
  Requires an authenticated session.
  
  Get currencies configured for this organization
  """
  currencies: [Currency!]!
  """
  Requires at least one of the permissions `settings:currency:read` or `settings:tenant:read`.
  
  Returns one currency. Requires permission to read currency or tenant settings.
  """
  currency(
    """The ID of the currency."""
    id: String!
  ): Currency!
  """
  Requires permission `customers:customer:read`.
  
  Returns one customer by ID, if the signed-in user may see it. Needs the customers read permission.
  """
  customer(
    """The ID of the customer."""
    id: ID!
  ): Customer!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the signed-in customer's company account: its name and code, credit limit, current balance and available credit. Available credit is empty when the credit limit is not enforced.
  """
  customerAccountInfo: CustomerAccountInfo!
  """
  Requires a customer (portal or buyer app) session.
  
  The addresses this login may use. An owner-assigned buyer sees ONLY the addresses assigned to them; assigned nothing = the whole account address book (unrestricted), never none.
  """
  customerAddresses: [CustomerAddress!]!
  """
  Requires at least one of the permissions `analytics:sales:read` or `dashboard:main:read`.
  
  Customer analytics for a period. Limited to the customers you may see.. Needs the sales analytics or dashboard read permission.
  """
  customerAnalytics(
    """The reporting period to analyse."""
    period: AnalyticsPeriod!
  ): CustomerAnalytics!
  """
  Requires a customer (portal or buyer app) session.
  
  Partner-wide approval history (all statuses), newest first. Approvers only. screen 14.
  """
  customerApprovalHistory(
    """Which page to return, and optional search text."""
    pagination: CustomerPaginationInput
  ): CustomerOrderApprovalConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  Lists the pictures the seller has set for variant attribute values, such as colour swatches. Values without a picture are not listed.
  """
  customerAttributeValuePictures: [CustomerAttributePicture!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Seller bank details for EFT (PortalConfiguration.displayBankAccountId). With orderId, paymentReference is "<customerCode> / <orderNumber>"; null orderId → no reference. screen 9.
  """
  customerBankDetails(
    """The order the bank details are for. Omit for the organization default."""
    orderId: ID
  ): CustomerBankDetails
  """
  Requires a customer (portal or buyer app) session.
  
  branch addresses of the caller's partner. CUSTOMER_ADMIN sees all; other roles see only their assigned branches (the picker set). Includes member/approver summaries and pendingApprovalCount (EDGE #4).
  """
  customerBranches: [CustomerBranch!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Lists the brands that have active products, with how many each has.
  """
  customerBrands(
    """
    Only brands with products in this category or beneath it; the counts cover that category too.
    """
    categoryId: ID
  ): [CustomerBrand!]!
  """
  Requires a customer (portal or buyer app) session.
  
  THIS partner's shared buying lists — every colleague at the customer company sees the same lists. Totals computed at read time; canEdit/canDelete are computed for the CALLING buyer. screen 12.
  """
  customerBuyingLists: [CustomerBuyingListView!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the signed-in customer's cart with each line priced live for the delivery address or branch in use.
  """
  customerCart: CartType!
  """
  Requires a customer (portal or buyer app) session.
  
  Server-side re-priced bill for the current cart (step 4). Every line is re-resolved fresh — never the stored cart price — and throws NO_PRICE_IN_CURRENCY if any line cannot be priced in the org currency.
  """
  customerCartBill(
    """
    the chosen live delivery option (customerDeliveryOptions). Without it a live-quote store returns deliveryFee null and deliverySelectionRequired true.
    """
    deliveryOptionId: ID
  ): CartBill!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the item count and total of the signed-in customer's cart, for a header badge. It uses the same customer and address as the cart.
  """
  customerCartSummary: CartSummary!
  """
  Requires a customer (portal or buyer app) session.
  
  Searches the storefront catalog for a signed-in customer: products, brands and categories visible on the storefront. The organization comes from the customer's sign-in.
  """
  customerCatalogSearch(
    """The maximum number of results. Defaults to 10."""
    limit: Int! = 10
    """The text to search for."""
    query: String!
    """
    Only search these result types. It can narrow the search but never widen it beyond products, brands and categories.
    """
    types: [GlobalSearchType!]
  ): CustomerCatalogSearchResult!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the category tree of the catalogue with a count of products under each category. Categories with no products are left out.
  """
  customerCategories(
    """
    Count only this brand's products, so the tree lists just the categories the brand sells in.
    """
    brandId: ID
  ): [CustomerCategory!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Lists the direct child categories of one category, one page at a time, with the number of products under each. Without a parent it lists the top-level categories.
  """
  customerCategoryChildren(
    """The cursor from the previous page; leave empty for the first page."""
    cursor: String
    """Children per page, from 1 to 100. Defaults to 50."""
    limit: Int = 50
    """
    The category whose children to list. Leave empty, with no slug, for the top level.
    """
    parentId: ID
    """Only children whose name matches this text."""
    search: String
    """The parent category's code, used when no parent ID is given."""
    slug: String
  ): CustomerCategoryConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns a category detail (subcategories) by slug.
  """
  customerCategoryDetail(
    """The slug that identifies the record."""
    slug: String!
  ): CategoryDetail!
  """
  Requires permission `commissions:commission:read`.
  
  Lists the commission rates set for specific customers. A rep, or a manager's subtree, sees only the customers in their own book. Requires permission to read commissions.
  """
  customerCommissionRates: [CustomerCommissionRate!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the signed-in customer's home summary: open orders, recent orders, quotes, invoices and balances. Order figures follow the customer's branch visibility; quotes, invoices and balances cover the whole company. A part that cannot be read is reported as unavailable, not as zero.
  """
  customerDashboard: CustomerDashboard!
  """
  Requires a customer (portal or buyer app) session.
  
  P6: live delivery options for the current cart to an orderable address. FLAT stores return mode FLAT and no options (the bill carries the fee). LIVE_QUOTE stores return priced options whose id is passed back as deliveryOptionId; code NO_DELIVERY_OPTIONS means delivery is unavailable to this address.
  """
  customerDeliveryOptions(
    """The ID of the address."""
    addressId: ID!
  ): CheckoutDeliveryOptions!
  """
  Requires permission `analytics:sales:read`.
  
  Customer engagement analytics over a date range, limited to what your role may see: sales reps see their own records, admins see everything by default, and other staff see their team.. Needs the sales analytics read permission.
  """
  customerEngagementAnalytics(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): CustomerEngagementAnalytics!
  """
  Requires a customer (portal or buyer app) session.
  
  Partner-wide frequently-bought items (attribution), repriced server-side. screen 6.
  """
  customerFrequentlyBought(
    "Maximum number of records to return."
    limit: Int
  ): [CustomerFrequentItem!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Lists the entry points that start the seller's guided buying flows in the buyer app.
  """
  customerGuidedEntries: GuidedEntryMap!
  """
  Requires a customer (portal or buyer app) session.
  
  Lists the guided buying flows the seller has set up for the buyer app.
  """
  customerGuidedFlows: [GuidedFlow!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the next step of a guided buying flow for the choices made so far. A flow that does not exist, or is not offered to buyers, is refused.
  """
  customerGuidedStep(
    """
    What the flow was opened from; ignored unless it is this tenant's and opens this flow
    """
    entry: GuidedEntryInput
    """The ID of the guided flow."""
    flowId: ID!
    """The choices made so far, in order. Empty to get the first step."""
    path: [GuidedPickInput!]!
  ): GuidedStepResult!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the display facts of the given product variants that guided flows show on their option cards.
  """
  customerGuidedVariantFacts(
    """The IDs of the variants to return facts for."""
    variantIds: [ID!]!
  ): [GuidedVariantFacts!]!
  """
  Requires permission `analytics:sales:read`.
  
  Analytics for one customer over a date range, for the Insights tab of the customer record. A customer outside your book is refused with the same not-found a missing one gets. Needs the sales analytics read permission.
  """
  customerInsights(
    """The ID of the customer."""
    partnerId: ID!
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): CustomerInsights!
  """
  Requires a customer (portal or buyer app) session.
  
  Base64 PDF of one of THIS partner's invoices (mirrors the staff pdf resolver)..
  """
  customerInvoicePdf(
    """The ID of the invoice."""
    invoiceId: ID!
  ): String!
  """
  Requires a customer (portal or buyer app) session.
  
  Invoices-screen KPI tiles (per-currency outstanding / not-yet-due / overdue) + server-computed available credit. screen 10.
  """
  customerInvoiceSummary: CustomerInvoiceSummary!
  """
  Requires a customer (portal or buyer app) session.
  
  Customer portal: lists the signed-in customer's own sales invoices, paged. Draft, cancelled and voided invoices are not shown. Needs a customer (portal or buyer app) session.
  """
  customerInvoices(
    """Paging and search: page (from 1), limit and an optional search text."""
    filter: CustomerPaginationInput
  ): CustomerInvoiceConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  The CALLER'S OWN parked checkout requests — pending, plus recently declined so a rejection is never silent. Not approver-gated (scoped to requestedById), because this is what tells a buyer where their held order went; approved requests are omitted since they have become real orders the order list already shows.
  """
  customerMyApprovalRequests: [CustomerOrderApprovalView!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the signed-in customer's price for a variant at a quantity, in the unit of measure given, or the variant's base unit when none is given.
  """
  customerMyVariantPrice(
    """How many units to price. Defaults to 1 when omitted or not above zero."""
    quantity: Int
    """The ID of the unit of measure to price the variant in."""
    uomId: String
    """The ID of the variant."""
    variantId: String!
  ): CustomerVariantPrice!
  """
  Requires a customer (portal or buyer app) session.
  
  Customer portal: the full detail of one of the signed-in customer's own orders, within the caller's visibility scope. Needs a customer (portal or buyer app) session.
  """
  customerOrderDetail(
    """The ID of the order."""
    orderId: ID!
  ): CustomerOrderDetail!
  """
  Requires a customer (portal or buyer app) session.
  
  "Payment under review" overlays for a batch of orders (AWAITING_PAYMENT + pending COLLECTION payment — DERIVED, never a backend status). screen 8.
  """
  customerOrderPaymentOverlays(
    """The IDs of the orders."""
    orderIds: [ID!]!
  ): [CustomerOrderPaymentOverlay!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Base64 PDF of one of THIS partner's sales orders..
  """
  customerOrderPdf(
    """The ID of the order."""
    orderId: ID!
  ): String!
  """
  Requires a customer (portal or buyer app) session.
  
  Customer portal: lists the signed-in customer's own orders, paged and filterable, within the caller's visibility scope. Needs a customer (portal or buyer app) session.
  """
  customerOrders(
    """Paging, search and status filters."""
    filter: CustomerOrderFilterInput
  ): CustomerOrderConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  Paginated partner purchase history for the Quick order tab. screen 6.
  """
  customerPastPurchases(
    """Which page to return, and optional search text."""
    pagination: CustomerPaginationInput
  ): CustomerPastPurchaseConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  Customer portal: lists the signed-in customer's own payments, paged. Draft, cancelled, reversed, refunded and awaiting-approval payments are not shown. Needs a customer (portal or buyer app) session.
  """
  customerPayments(
    """Which page to return, and optional search text."""
    filter: CustomerPaginationInput
  ): CustomerPaymentConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  Approval requests awaiting THIS user's decision (approvers only). screen 14.
  """
  customerPendingApprovals: [CustomerOrderApprovalView!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the PLP_BANNER for the given category slug. Falls back to a banner with no categorySlug (global) when no per-category row exists. Null when neither is authored.
  """
  customerPlpBanner(
    """The slug of the category."""
    categorySlug: String!
  ): InfoStripSection @deprecated(reason: "Kept only for buyer-app versions released before the app read the storefront theme (D-116): they still call it. The Home CMS is retired (D-115/D-116); current apps read customerStorefrontPage. Remove once those versions are retired.")
  """
  Requires a customer (portal or buyer app) session.
  
  Finds the active product that has a variant with the given SKU and returns it with that variant.
  """
  customerProductBySku(
    """The SKU to look up."""
    sku: String!
  ): CustomerProductDetail!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns one active product with its variants, units of measure, images, attributes and the signed-in customer's prices and stock.
  """
  customerProductDetail(
    """
    Kept for compatibility; it does not change which prices or discounts apply.
    """
    addressId: ID
    """The ID of the product."""
    productId: ID!
  ): CustomerProductDetail!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the filter choices and their counts (categories, brands, price range, attributes) for the products that match a filter, so a storefront can draw its filter panel. Counts follow the same narrowing as the product list.
  """
  customerProductFacets(
    """
    The filters the counts are computed for; paging and sort order are ignored.
    """
    filter: CustomerProductFilterInput
  ): CustomerProductFacets!
  """
  Requires a customer (portal or buyer app) session.
  
  Lists the catalogue products a signed-in customer can buy, one page at a time, with filters for category, brand, price, stock and attributes. Prices are the signed-in customer's own. When search text is given, the first page also records the search as buyer activity.
  """
  customerProducts(
    """Search text, filters, sort order and paging for the list."""
    filter: CustomerProductFilterInput
  ): CustomerProductConnection!
  """
  Requires permission `sales:sales_order:read`.
  
  The items a customer buys most often, at product, variant and unit level, for a rep's reorder view. Reps see only customers in their own scope. limit defaults to 30. Needs the sales order read permission.
  """
  customerPurchaseHistory(
    """Maximum number of items to return. Defaults to 30."""
    limit: Int = 30
    """The ID of the customer."""
    partnerId: ID!
  ): [CustomerPurchaseHistoryItem!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Distinct variantIds THIS partner has ever ordered ("Bought before" badges)..
  """
  customerPurchasedVariantIds: [ID!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Full detail of one of THIS partner's quotes. screen 13.
  """
  customerQuoteDetail(
    """The ID of the quote."""
    quoteId: ID!
  ): CustomerQuoteDetail!
  """
  Requires a customer (portal or buyer app) session.
  
  Base64 PDF of one of THIS partner's quotes..
  """
  customerQuotePdf(
    """The ID of the quote."""
    quoteId: ID!
  ): String!
  """
  Requires a customer (portal or buyer app) session.
  
  Customer portal: lists the signed-in customer's own quotes, paged, with optional status and search filters. Needs a customer (portal or buyer app) session.
  """
  customerQuotes(
    """Paging, search and status filters."""
    filter: CustomerQuoteFilterInput
  ): CustomerQuoteConnection!
  """
  Requires permission `communications:message:send`.
  
  Tells whether a reminder of one kind can be sent to a customer now, and the reason when it cannot. The customer must be in the caller's own book. Requires permission to send messages.
  """
  customerReminderEligibility(
    """The customer and the kind of reminder."""
    input: CustomerReminderInput!
  ): CustomerReminderEligibilityGql!
  """
  Requires permission `customers:customer:read`.
  
  Returns report data for the customers the signed-in user may see, optionally filtered. Needs the customers read permission.
  """
  customerReports(
    """Optional filters that narrow the report."""
    filters: CustomerReportFiltersInput
  ): CustomerReportsData!
  """
  Requires a customer (portal or buyer app) session.
  
  Resolve pasted "code, qty[, uom]" lines to purchasable variants (SKU_EXACT then NAME_FUZZY), repriced server-side. screen 6 "Paste list".
  """
  customerResolveOrderLines(
    """The details of the customer resolve order lines request."""
    input: CustomerResolveOrderLinesInput!
  ): CustomerResolvedOrderLines!
  """
  Requires a customer (portal or buyer app) session.
  
  Delivered orders still inside PortalConfiguration.returnsWindowDays, with their returnable lines. screen 15.
  """
  customerReturnableOrders: [CustomerReturnableOrder!]!
  """
  Requires a customer (portal or buyer app) session.
  
  THIS partner's returns, newest first (Requested | Collected | Credit note issued). screen 15.
  """
  customerReturns(
    """Which page to return, and optional search text."""
    pagination: CustomerPaginationInput
  ): CustomerReturnConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the active SEARCH_BANNER for the organization, or null when admin has not authored one.
  """
  customerSearchBanner: InfoStripSection @deprecated(reason: "Kept only for buyer-app versions released before the app read the storefront theme (D-116): they still call it. The Home CMS is retired (D-115/D-116); current apps read customerStorefrontPage. Remove once those versions are retired.")
  """
  Requires a customer (portal or buyer app) session.
  
  the courier's live position for one of the buyer's shipments (an order shipment this buyer may see, or the company's own return pickup). Null unless CustomerShipment.liveLocationAvailable (always null for an order shipment when the store's customer tracking is below full) — and still null while the carrier has no position. Another company's shipment is not found. Cached 15 s per shipment; poll no faster.
  """
  customerShipmentLiveLocation(
    """The ID of the shipment."""
    shipmentId: ID!
  ): ShipmentLiveLocation
  """
  Requires a customer (portal or buyer app) session.
  
  Per-currency account statement over a window: opening + invoices − payments/credits == closing; Σ rows == the invoices-screen KPI tiles. screen 11.
  """
  customerStatement(
    """The first day of the statement."""
    from: DateTime!
    """The last day of the statement."""
    to: DateTime!
  ): CustomerStatement!
  """
  Requires a customer (portal or buyer app) session.
  
  Base64 PDF rendering of customerStatement (same numbers — /8). screen 11.
  """
  customerStatementPdf(
    """The first day of the statement."""
    from: DateTime!
    """The last day of the statement."""
    to: DateTime!
  ): String!
  """
  Requires at least one of the permissions `customers:customer:list` or `customers:customer:read`.
  
  Returns summary counts for the customers the signed-in user may see. Needs the customers read or list permission.
  """
  customerStatistics: CustomerStatistics!
  """
  Requires a customer (portal or buyer app) session.
  
  A page of this store's LIVE published storefront theme as the buyer app draws it (never the draft; the basic default theme when nothing is published): the home page, the Search template, or the Category template a category uses (its assigned alternate, else the default). Only sections shown in the app.
  """
  customerStorefrontPage(
    """
    CATEGORY only: the category shown, to find the alternate template assigned to it. Ignored for any other page.
    """
    categoryId: ID
    """The page to return."""
    page: StorefrontAppPageKind!
  ): StorefrontAppPage!
  """
  Requires a customer (portal or buyer app) session.
  
  All CUSTOMER users under THIS partner with role/limit/approver flags. screen 16.
  """
  customerTeam: [CustomerTeamMember!]!
  """
  Requires at least one of the permissions `customers:customer:read`, `settings:customer_tiers:read` or `settings:tenant:read`.
  
  Returns the customer tier setup: whether tiers are on, and each tier's name, rank, threshold and discount scheme. Requires permission to read customer tier or tenant settings, or customers (the customer list shows each tier).
  """
  customerTierConfig: CustomerTierConfig!
  """
  Requires at least one of the permissions `customers:customer:read` or `settings:customer_tiers:read`.
  
  Returns one customer's tier and whether that tier is locked against automatic changes. Fails if the customer does not exist. Requires permission to read customer tier settings or customers.
  """
  customerTierStatus(
    """The ID of the customer."""
    customerId: String!
  ): CustomerTierStatus!
  """
  Requires an authenticated session.
  
  Returns whether the customer tiers module is switched on, so the console and the sales app can hide tier screens when it is off. Readable by every staff user.
  """
  customerTiersModuleEnabled: Boolean!
  """
  Requires a customer (portal or buyer app) session.
  
  The in-app tracking view for one of the buyer's shipments (an order shipment this buyer may see, or the company's own return pickup): the shipment, its progress steps and when the carrier was last asked. Opening it asks the carrier (the answer is reused for 60 s); refresh: true asks again unless the last ask was under 30 s ago. A carrier failure sets updateDelayed and still returns the saved timeline. Another company's shipment is not found. Shaped by the store's customer tracking setting: progress-only hides the courier, number and link; order-status-only returns null for an order shipment (show no shipment section).
  """
  customerTrackShipment(
    """
    True to fetch fresh tracking from the courier instead of using the stored status.
    """
    refresh: Boolean = false
    """The ID of the shipment."""
    shipmentId: ID!
  ): CustomerShipmentTracking
  """
  Requires at least one of the permissions `payments:invoice:create`, `products:pricing:read`, `purchase:debit_note:create`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:credit_note:create`, `sales:quote:create`, `sales:quote:update`, `sales:sales_invoice:create`, `sales:sales_order:create` or `sales:sales_order:update`.
  
  Returns the price of a variant for a unit and quantity, including tiers, packs, tax and automatic discounts, through the same pricing every surface uses. In a foreign currency it returns only a price set in that currency and reports that none exists rather than converting, unless a conversion rate is supplied. Needs the pricing read permission, or permission to create or edit a document that prices lines. A customer outside your book is reported as not found.
  """
  customerVariantPrice(
    """
    Opt-in conversion rate, where 1 unit of the currency equals this many base units. A foreign currency with no price of its own is then priced by converting the base price. A price set in that currency always wins.
    """
    convertAtRate: Float
    """
    ISO 4217 currency code to price in. Omit it to price in the base currency.
    """
    currency: String
    """
    The ID of the customer the price is for. Optional: it only decides which discount schemes and tax exemptions apply.
    """
    partnerId: String
    """The quantity to price. Defaults to 1 when omitted or not above zero."""
    quantity: Float
    """
    The calendar day, as YYYY-MM-DD, on which the customer's tax exemption is judged. Defaults to today. Anything that is not a calendar day is refused.
    """
    taxDate: String
    """The ID of the unit of measure to price the variant in."""
    uomId: String
    """The ID of the variant."""
    variantId: String!
  ): CustomerVariantPrice!
  """
  Requires at least one of the permissions `customers:customer:list`, `customers:customer:read`, `payments:collection:create`, `payments:invoice:create`, `products:discount:update`, `sales:credit_note:create`, `sales:quote:create` or `sales:sales_order:create`.
  
  Lists the customers the signed-in user may see, newest first. Reps see their own customers, managers see their reporting team's, and admins see all. Needs a customer read grant or a grant to raise a customer document (quote, sales order, invoice, collection, credit note).
  """
  customers(
    """
    Only customers entered by this user. It can narrow the customers you may see but never widen them.
    """
    enteredBy: String
    """
    Matches, case-insensitively and in part, a customer's name, code, display name, legal name or customer code, or the value or name of one of its contacts.
    """
    search: String
  ): [Customer!]!
  """
  Requires at least one of the permissions `customers:customer:list` or `customers:customer:read`.
  
  Returns the customer book one page at a time, for apps that sync for offline use. Limited to the customers the signed-in user may see. Pass updatedAfter for a delta pull, which also includes deleted customers, and page with the returned nextCursor. Needs the customers read or list permission.
  """
  customersPage(
    """
    The nextCursor returned with the previous page. Leave it out for the first page.
    """
    cursor: String
    """
    Only customers entered by this user. It can narrow the customers you may see but never widen them.
    """
    enteredBy: String
    """
    Matches, case-insensitively and in part, a customer's name, code, display name, legal name or customer code, or the value or name of one of its contacts.
    """
    search: String
    """The page size. Defaults to 100."""
    take: Int = 100
    """Only customers changed after this time, including deleted ones."""
    updatedAfter: DateTime
  ): CustomersPage!
  """
  Requires an authenticated session.
  
  The figures for the dashboard home screen over a date range, limited to what your role may see: sales reps see their own records, admins see everything by default, and other staff see their team.
  """
  dashboardHome(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): DashboardHome!
  """
  Requires permission `dashboard:main:read`.
  
  Headline dashboard statistics for your organization. Limited to the customers you may see. Needs the dashboard read permission.
  """
  dashboardStats: DashboardStats!
  """
  Requires permission `purchase:debit_note:read`.
  
  Returns one debit note by ID. Needs the debit notes feature on your plan.
  """
  debitNote(
    """The ID of the debit note."""
    id: ID!
  ): DebitNote!
  """
  Requires permission `purchase:debit_note:read`.
  
  Lists the audit trail of one debit note: who changed it, when, and what changed. Needs the debit notes feature on your plan.
  """
  debitNoteAuditLogs(
    """The ID of the debit note."""
    debitNoteId: ID!
  ): [AuditLog!]!
  """
  Requires permission `purchase:debit_note:list`.
  
  Returns summary figures for debit notes, such as counts by status. Needs the debit notes feature on your plan.
  """
  debitNoteSummary: DebitNoteSummary!
  """
  Requires permission `purchase:debit_note:list`.
  
  Lists debit notes with optional filters and `skip` / `take` paging. Needs the debit notes feature on your plan.
  """
  debitNotes(
    """Filter criteria for debit note records. Omit to match all."""
    filters: DebitNoteFiltersInput
    """Only debit notes for this partner."""
    partnerId: ID
    "Number of records to skip. Send with take to page through results."
    skip: Int
    "Number of records to return."
    take: Int
  ): [DebitNote!]!
  """
  Requires permission `purchase:debit_note:list`.
  
  Returns how many debit notes match the filters, without loading them. Needs the debit notes feature on your plan.
  """
  debitNotesCount(
    """Filter criteria for debit note records. Omit to match all."""
    filters: DebitNoteFiltersInput
  ): Int!
  """
  Requires an authenticated session.
  
  Returns the warehouse a new document should start with: the customer's own default if one is given and set, else the organization's default warehouse, else an active warehouse chosen the same way every time. Fails when the organization has no active warehouse.
  """
  defaultWarehouse(
    """
    The ID of a customer whose own default warehouse should apply first. Omit it for the organization's default.
    """
    partnerId: ID
  ): Warehouse!
  """
  Requires permission `settings:sales:read`.
  
  Tests a box being added or edited with one product variant: how many the packing engine puts in one such box, what limits it, and a suggested arrangement by shape. Stores nothing. Requires permission to read sales settings.
  """
  deliveryBoxFitPreview(
    """The box's inside size and weights, and the variant to test it with."""
    input: DeliveryBoxFitPreviewInput!
  ): DeliveryBoxFitPreview!
  """
  Requires permission `settings:sales:read`.
  
  Lists the standard box sizes offered when adding a box. Requires permission to read sales settings.
  """
  deliveryBoxPresets: [DeliveryBoxPreset!]!
  """
  Requires permission `settings:sales:read`.
  
  Returns what customers see for delivery: how they choose (all options, speeds or one price), which courier details show, the tracking level and the allowed services. These are the saved settings, or the defaults when none were saved, leaving out partners that have been removed. Requires permission to read sales settings.
  """
  deliveryCustomerDisplay: DeliveryCustomerDisplay!
  """
  Requires permission `settings:sales:read`.
  
  Previews, without saving anything, what customers and staff would see for one address under the display settings given: live carrier prices shaped for each app, plus the staff list. No option is redeemed and nothing is recorded. It calls the carriers, so it needs the delivery partners plan feature, and permission to read sales settings.
  """
  deliveryCustomerDisplayPreview(
    """
    The address, an optional customer, and the unsaved display settings to preview.
    """
    input: DeliveryCustomerDisplayPreviewInput!
  ): DeliveryCustomerDisplayPreview!
  """
  Requires permission `settings:sales:read`.
  
  Returns the organization's box packing settings, or the defaults with no boxes when none were saved. Requires permission to read sales settings.
  """
  deliveryPackingSettings: DeliveryPackingSettings!
  """
  Requires permission `settings:integration:read`.
  
  Lists the organization's delivery partner configurations. Secrets are never returned. Requires permission to read integrations.
  """
  deliveryPartnerConfigs: [DeliveryPartnerConfigGql!]!
  """
  Requires permission `settings:integration:read`.
  
  Lists the delivery partners (couriers) the workspace can connect, each with what it declares: what it can do, its credential and settings fields, the countries and currencies it serves, and how its webhooks authenticate. Requires permission to read integrations.
  """
  deliveryPartnerProviders: [DeliveryPartnerProviderInfo!]!
  """
  Requires permission `settings:sales:read`.
  
  Lists the courier services each delivery partner has returned, grouped by partner, with when each was last seen, an example price and whether customers are offered it. Requires permission to read sales settings.
  """
  deliverySeenServices: [DeliverySeenServiceGroup!]!
  """
  Requires permission `settings:sales:read`.
  
  Returns the delivery settings: how the delivery fee is charged, the flat fee and free-delivery thresholds, the default pickup warehouse and customer delivery emails. Requires permission to read sales settings.
  """
  deliverySettings: DeliverySettingsGql!
  """
  Requires permission `products:discount:read`.
  
  Returns one discount scheme. Fails if the scheme does not exist. Needs the discounts read permission.
  """
  discountScheme(
    """The ID of the discount scheme."""
    id: String!
  ): DiscountScheme!
  """
  Requires permission `products:discount:list`.
  
  Lists the organization's discount schemes, optionally filtered and paged. A scheme's customers and products are loaded only when the query selects them. Omit skip and take to return every scheme; use discountSchemesCount for the total. Needs the discounts list permission.
  """
  discountSchemes(
    """
    Optional filters: search text, status, scope, active flag, currency and sort order.
    """
    filter: DiscountSchemeFilterInput
    """How many schemes to skip."""
    skip: Int
    """How many schemes to return."""
    take: Int
  ): [DiscountScheme!]!
  """
  Requires permission `products:discount:list`.
  
  Returns how many discount schemes match the same filter as discountSchemes, ignoring paging, for a pager. Needs the discounts list permission.
  """
  discountSchemesCount(
    """Optional filters. The same ones as discountSchemes."""
    filter: DiscountSchemeFilterInput
  ): Int!
  """
  Requires permission `products:discount:read`.
  
  Returns discount scheme counts for the whole organization, such as total, active, expired and scheduled schemes, counted by the database over every scheme. Needs the discounts read permission.
  """
  discountSchemesSummary: DiscountSchemesSummary!
  """
  Requires permission `products:discount:read`.
  
  Returns how much a discount scheme has been used, taken from the organization's sales orders. Cancelled and deleted orders are left out. Fails if the scheme does not exist. Needs the discounts read permission.
  """
  discountUsageStats(
    """The ID of the discount scheme."""
    schemeId: String!
  ): DiscountUsageStats!
  """
  Requires permission `settings:documents:read`.
  
  The tenant's resolved brand identity (logo, company, accent, footer) — one value each, applied to every PDF and every document email. Falls back to the legacy per-document-type configs when no brand is saved yet.
  """
  documentBrand: DocumentBrandConfig!
  """
  Requires at least one of the permissions `approvals:bills:approve`, `approvals:credit:approve`, `approvals:credit_notes:approve`, `approvals:discounts:approve`, `approvals:large_orders:approve`, `approvals:order_changes:approve`, `approvals:payments:verify`, `approvals:stock_adjustments:approve`, `approvals:supplier_payments:approve`, `inventory:stock_adjustment:create`, `payments:collection:create`, `payments:collection:update`, `payments:payment:allocate`, `payments:payment:create`, `payments:payment:update`, `purchase:grn:create`, `purchase:grn:update`, `purchase:payment:allocate`, `purchase:payment:create`, `purchase:payment:update`, `purchase:purchase_invoice:create`, `purchase:purchase_order:approve`, `sales:credit_note:create`, `sales:sales_order:confirm`, `sales:sales_order:deliver`, `sales:sales_order:ship`, `sales:sales_order:update`, `sales:shipment:create` or `sales:shipment:update`.
  
  A document's control status for its banner: its latest five approval requests and the enforced control block that still stands on it, if any.
  """
  documentControlStatus(
    """The document's ID."""
    documentId: ID!
    """The document's type, e.g. SalesOrder or GoodsReceipt."""
    documentType: String!
  ): DocumentControlStatus!
  """
  Requires at least one of the permissions `settings:documents:read` or `settings:email:read`.
  
  Durable document-delivery outbox rows for this org, newest first.
  """
  documentDeliveries(
    "Number of records to skip. Send with take to page through results."
    skip: Int = 0
    """Only deliveries with this status."""
    status: OutboxDeliveryStatus
    "Number of records to return."
    take: Int = 25
  ): OutboxDeliveryPage!
  """
  Requires permission `settings:documents:read`.
  
  Every saved email wording override for this org (subject + body per email type). Types without a row keep the registry wording.
  """
  documentEmailCopies: [DocumentEmailCopy!]!
  """
  Requires permission `settings:documents:read`.
  
  Every outbound document email template that can be previewed, read straight off the registry so the settings list cannot drift from what sends.
  """
  documentEmailTemplates: [DocumentEmailTemplateInfo!]!
  """
  Requires at least one of the permissions `settings:documents:update` or `settings:tenant:read`.
  
  Returns the last document number issued for a document type across all periods, such as the latest invoice or quote number, or null when none has been issued. Requires permission to read tenant settings or to update document settings.
  """
  documentNumberLastIssued(
    """The document type to look up."""
    docType: DocumentNumberType!
  ): String
  """
  Requires at least one of the permissions `settings:documents:update` or `settings:tenant:read`.
  
  Returns the document numbering series for invoices, quotes, orders and the other document types: each one's prefix, separator, padding, date format, reset policy and next number. Requires permission to read tenant settings or to update document settings.
  """
  documentNumbering: DocumentNumberingSettings!
  """
  Requires permission `settings:documents:read`.
  
  The saved document template config for a document type (null if unset).
  """
  documentTemplateConfig(
    """The kind of document, for example a quote or an invoice."""
    documentType: String!
  ): DocumentTemplateConfig
  """
  Requires permission `settings:email:read`.
  
  Returns the organization's email sending configuration, or null when none exists. Requires permission to read email settings.
  """
  emailConfig: EmailConfig
  """
  Requires permission `sales:quote:read`.
  
  Lists the caller's own unsent email drafts, most recently updated first. Requires permission to read quotes.
  """
  emailDrafts: [EmailDraft!]!
  """
  Requires at least one of the permissions `settings:email:update` or `settings:tenant:update`.
  
  Returns the state of sender-domain verification: whether it is available on this deployment, the organization's domain and its DNS records, the address mail is currently sent from and why, and the platform's own sending domain. Requires permission to update email settings.
  """
  emailSenderSetup: EmailSenderSetup!
  """
  Requires permission `settings:integration:read`.
  
  Lists the organization's integrations that are switched on. Secrets are never returned. Requires permission to read integrations.
  """
  enabledIntegrations: [IntegrationSetting!]!
  """
  Requires an authenticated session.
  
  Returns the exchange rate between two currencies for a date. The organization's own rate in force on that day wins over the platform-wide rate. It is a rate for documents, not a price.
  """
  exchangeRate(
    """
    The document's date (YYYY-MM-DD or ISO). The tenant's rate in force on that day wins over the global feed; omitted = today.
    """
    date: String
    """The currency code to convert from."""
    fromCurrency: String!
    """The currency code to convert to."""
    toCurrency: String!
  ): ExchangeRate!
  """
  Requires at least one of the permissions `settings:currency:read` or `settings:tenant:read`.
  
  Lists every exchange rate from a base currency, or all of them when none is given: each target currency, the rate and when it was last updated. The rates are shared by every organization. Requires permission to read currency or tenant settings.
  """
  exchangeRates(
    """The currency code to list rates from. Omit it to list every rate."""
    baseCurrency: String
  ): [ExchangeRate!]!
  """
  Requires at least one of the permissions `analytics:invoices:read` or `analytics:payments:read`.
  
  Financial analytics for a period. Limited to the customers you may see.. Needs the invoices or payments analytics read permission.
  """
  financialAnalytics(
    """
    Does not change the figures: totals are always reported in the organization's base currency.
    """
    currency: String
    """The reporting period to analyse."""
    period: AnalyticsPeriod!
  ): FinancialAnalytics!
  """
  Requires a customer (portal or buyer app) session.
  
  Products this buyer's company orders repeatedly — 'Shop your regulars'. Derived from their own order history, company-scoped like every other order read. A line bought only once is excluded: 'your regulars' has to mean something.
  """
  frequentlyOrderedProducts(
    "Maximum number of records to return."
    limit: Int
  ): [MobileFrequentProduct!]!
  """
  Requires an authenticated session.
  
  The base unit of a category, or null when the category has none.
  """
  getBaseUOM(
    """The unit category."""
    category: UOMCategory!
  ): UnitOfMeasure
  """
  Requires permission `categories:category:create`.
  
  Returns a sample CSV file for bulkImportCategories, with the column headers it expects and example rows. A child row must come below the row that defines its parent and refer to it by code. Requires permission to create categories.
  """
  getCategoryImportTemplate: String!
  """
  Public: no authentication required.
  
  Lists the organizations a Google account already belongs to, with its name and picture, for the sign-up page. Needs no sign-in.
  """
  getExistingOrganizations(
    """The Google ID token that proves the account."""
    googleToken: String!
  ): ExistingOrganizationsResponse!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists return requests (RMAs) still waiting for approval, newest first. Customer returns need the credit notes list permission and supplier returns the debit notes list permission.
  """
  getPendingRMAs: [ProductReturn!]!
  """
  Requires permission `products:product:read`.
  
  One pack (a unit on a product or variant) by its id, or null when it was removed or is not this organization's.
  """
  getProductUOM(
    """The ID of the product unit (pack)."""
    id: String!
  ): ProductUOM
  """
  Requires an authenticated session.
  
  List the units (packs) set up on a product, optionally for one variant. Packs on a deactivated unit are left out unless includeInactive is true.
  """
  getProductUOMs(
    """Set to true to include packs on deactivated units. Defaults to false."""
    includeInactive: Boolean
    """The ID of the product."""
    productId: String!
    """
    Limit the list to this variant's units: the product-wide ones plus the variant's own. Omit to list every row, as editor views do.
    """
    variantId: String
  ): [ProductUOM!]!
  """
  Requires at least one of the permissions `purchase:debit_note:read` or `sales:credit_note:read`.
  
  Returns one return from the invoice-based flow by ID. A customer return needs the credit notes read permission and a supplier return the debit notes read permission; a rep sees only their own customers' returns.
  """
  getReturn(
    """The ID of the return."""
    id: String!
  ): ProductReturn!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists returns with optional filters and page-number paging (`pagination` page and limit, 50 per page by default). Customer returns need the credit notes list permission and supplier returns the debit notes list permission; a rep sees only their own customers' returns.
  """
  getReturns(
    """Filter criteria for return records. Omit to match all."""
    filters: ReturnFilterInput
    """Which page to return."""
    pagination: PaginationInput
  ): ReturnListResponse!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists returns that have been received and are waiting for inspection. Customer returns need the credit notes list permission and supplier returns the debit notes list permission.
  """
  getReturnsAwaitingInspection: [ProductReturn!]!
  """
  Requires permission `sales:credit_note:list`.
  
  Lists the returns of one customer. Needs the credit notes list permission; a rep sees only their own customers' returns.
  """
  getReturnsByCustomer(
    """The ID of the customer."""
    customerId: String!
  ): [ProductReturn!]!
  """
  Requires permission `purchase:debit_note:list`.
  
  Lists the returns to one supplier. Needs the debit notes list permission.
  """
  getReturnsBySupplier(
    """The ID of the supplier."""
    supplierId: String!
  ): [ProductReturn!]!
  """
  Requires permission `sales:sales_order:read`.
  
  The order's lines that still have quantity left to invoice, with the invoiced and remaining quantity for each.
  """
  getSalesOrderItemsWithRemainingQuantity(
    """The ID of the sales order."""
    salesOrderId: ID!
  ): [SalesOrderItem!]!
  """
  Requires an authenticated session.
  
  Fetch one unit of measure by id, or null when it does not exist or was deleted.
  """
  getUOM(
    """The ID of the unit of measure."""
    id: String!
  ): UnitOfMeasure
  """
  Requires permission `products:product:read`.
  
  One unit conversion by its id, or null when it was deleted or is not this organization's.
  """
  getUOMConversion(
    """The ID of the conversion."""
    id: String!
  ): UOMConversion
  """
  Requires an authenticated session.
  
  List the conversions that start or end at a unit.
  """
  getUOMConversions(
    """The ID of the unit of measure."""
    uomId: String!
  ): [UOMConversion!]!
  """
  Requires permission `products:product:read`.
  
  Counts for the unit-of-measure settings page: total, active and inactive units, units per category, conversions, the five newest units and the base unit of each category. Needs the products read permission.
  """
  getUOMSummary: UOMSummary!
  """
  Requires an authenticated session.
  
  List the organization's units of measure, optionally filtered and sorted. Omit skip and take to get the whole list, for unit pickers; send both to page, and use getUOMsCount for the total.
  """
  getUOMs(
    """Optional filters and sorting."""
    filters: UOMFiltersInput
    """Number of units to skip. Send with take for paging."""
    skip: Int
    """
    Number of units to return. Omit skip and take to return the whole list.
    """
    take: Int
  ): [UnitOfMeasure!]!
  """
  Requires an authenticated session.
  
  List the active units in one category, for unit pickers. Send productId to list the units available for that product.
  """
  getUOMsByCategory(
    """The unit category."""
    category: UOMCategory!
    """The ID of a product to list the available units for."""
    productId: String
  ): [UnitOfMeasure!]!
  """
  Requires an authenticated session.
  
  Count the units of measure that match the same filters as getUOMs.
  """
  getUOMsCount(
    """The same filters as getUOMs."""
    filters: UOMFiltersInput
  ): Int!
  """
  Requires permission `sales:credit_note:list`.
  
  Lists warranty returns, with optional filters. Needs the credit notes list permission; a rep sees only their own customers' returns.
  """
  getWarrantyReturns(
    """Filter criteria for return records. Omit to match all."""
    filters: ReturnFilterInput
  ): [ProductReturn!]!
  """
  Requires permission `products:product:read`.
  
  Searches the console's records, for staff users only. Needs products:product:read. Result types you cannot read are dropped, and customers or documents outside your scope never appear, even as names.
  """
  globalSearch(
    """The maximum number of results. Defaults to 10."""
    limit: Int! = 10
    """The text to search for."""
    query: String!
    """
    Only search these result types. Leave out to search every type you may read.
    """
    types: [GlobalSearchType!]
  ): GlobalSearchResult!
  """
  Requires permission `purchase:grn:read`.
  
  Returns one goods receipt by ID. Needs the goods receipt (GRN) feature on your plan.
  """
  grn(
    """The ID of the goods receipt note."""
    id: ID!
  ): GRN!
  """
  Requires permission `purchase:grn:read`.
  
  Lists the audit trail of one goods receipt: who changed it, when, and what changed. Needs the goods receipt (GRN) feature on your plan.
  """
  grnAuditLogs(
    """The ID of the goods receipt note."""
    grnId: ID!
  ): [AuditLog!]!
  """
  Requires permission `purchase:grn:list`.
  
  Returns summary figures for goods receipts: counts and values by status, plus purchase order value that is approved, unreceivable or received without a purchase order. Needs the goods receipt (GRN) feature on your plan.
  """
  grnSummary: GRNSummary!
  """
  Requires permission `purchase:grn:list`.
  
  Lists goods receipts with optional filters and `skip` / `take` paging. Needs the goods receipt (GRN) feature on your plan.
  """
  grns(
    """Filter criteria for GRN records. Omit to match all."""
    filter: GRNFilterInput
    "Number of records to skip. Send with take to page through results."
    skip: Int
    "Number of records to return."
    take: Int
  ): [GRN!]!
  """
  Requires permission `purchase:grn:list`.
  
  Returns how many goods receipts match the filters, without loading them. Needs the goods receipt (GRN) feature on your plan.
  """
  grnsCount(
    """Filter criteria for GRN records. Omit to match all."""
    filter: GRNFilterInput
  ): Int!
  """
  Requires permission `settings:tenant:update`.
  
  Lists the product attributes a product finder can ask about, each with its values and how many active variants carry each. Attribute spellings that differ only by case count as one attribute. Requires permission to update tenant settings.
  """
  guidedFlowCatalogShape: [GuidedAttributeKey!]!
  """
  Requires permission `settings:tenant:update`.
  
  Previews one step of a product finder (guided flow) for the picks made so far, using a draft flow that has not been saved. The draft is validated as a save would validate it, and nothing is written. Requires permission to update tenant settings.
  """
  guidedFlowPreview(
    """Preview as if opened from this; ignored unless it would open this flow"""
    entry: GuidedEntryInput
    """The draft guided flow, in the shape the editor saves."""
    flow: JSON!
    """
    The picks made so far, each with the step it answered and the value chosen.
    """
    path: [GuidedPickInput!]!
  ): GuidedStepResult!
  """
  Requires permission `products:product:read`.
  
  Lists the product finders (guided flows) set up for the storefront or the order pad, optionally only those offered in one app. Requires permission to read products.
  """
  guidedFlows(
    """
    Only return the flows offered in this app. Omit it to return every flow.
    """
    surface: GuidedFlowSurface
  ): [GuidedFlow!]!
  """
  Requires at least one of the permissions `sales:sales_order:read` or `users:user:read`.
  
  Orders of one customer under one rep (chain-validated). Needs the sales order read or users read permission.
  """
  hierarchyCustomerOrders(
    """The details of the hierarchy orders request."""
    input: HierarchyOrdersInput!
  ): HierarchyOrderPage!
  """
  Requires at least one of the permissions `customers:customer:read`, `settings:user:read` or `users:user:read`.
  
  Aggregate cards for any node: team composition, customers, orders, revenue. Needs the users read, user settings read or customers read permission.
  """
  hierarchyNodeSummary(
    """Only activity on or after this date."""
    dateFrom: DateTime
    """Only activity on or before this date."""
    dateTo: DateTime
    """The ID of the user whose summary is returned."""
    userId: String!
  ): HierarchyNodeSummary!
  """
  Requires at least one of the permissions `customers:customer:read` or `users:user:read`.
  
  Customers under one sales rep with per-customer order stats. Needs the customers read or users read permission.
  """
  hierarchyRepCustomers(
    """The details of the hierarchy customers request."""
    input: HierarchyCustomersInput!
  ): HierarchyCustomerPage!
  """
  Requires at least one of the permissions `customers:customer:read`, `settings:user:read` or `users:user:read`.
  
  Top-level role tabs (display roles with counts), scoped to what the caller may see. Optional search (name/email/phone) and status narrow the counts while the tab set stays stable. Needs the users read, user settings read or customers read permission.
  """
  hierarchyRoleTabs(
    "Text to search for."
    search: String
    """Only users with this status."""
    status: String
  ): [HierarchyRoleTab!]!
  """
  Requires at least one of the permissions `customers:customer:read`, `settings:user:read` or `users:user:read`.
  
  Users of a role tab, or the direct reports of a manager — with subtree stats. Needs the users read, user settings read or customers read permission.
  """
  hierarchyUsers(
    """The details of the hierarchy users request."""
    input: HierarchyUsersInput!
  ): HierarchyUserPage!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the ordered list of HomeSection cells for the active address, from the retired Home CMS rows.
  """
  homeFeed(
    """
    The delivery address that decides what is in stock. Omit for the default address.
    """
    addressId: ID
  ): HomeFeed! @deprecated(reason: "Kept only for buyer-app versions released before the app read the storefront theme (D-116): they still call it. The Home CMS is retired (D-115/D-116); current apps read customerStorefrontPage. Remove once those versions are retired.")
  """
  Requires permission `products:import:read`.
  
  S2.2 — saved per-supplier column-mapping profiles for the org.
  """
  importMappingProfiles: [ImportMappingProfile!]!
  """
  Requires permission `sales:quote:read`.
  
  Lists email threads for the inbox, one page at a time, by folder and optional search text. A sales rep sees only the mail on quotes they may open. Requires permission to read quotes.
  """
  inboxThreads(
    """
    Optional page size (default 20), cursor, folder (default inbox) and search text.
    """
    input: InboxThreadsInput
  ): InboxConnection!
  """
  Requires permission `sales:quote:read`.
  
  Returns how many inbound customer emails in the inbox are still unread, counting only quotes the caller may open. Requires permission to read quotes.
  """
  inboxUnreadCount: Int!
  """
  Public: no authentication required.
  
  Lists the industries an organization can choose from, each with a value and a label.
  """
  industryOptions: [IndustryOption!]!
  """
  Requires permission `settings:integration:read`.
  
  Returns the organization's integration for one service, or null when it has none. Secrets are never returned. Requires permission to read integrations.
  """
  integrationByService(
    """The service to look up."""
    serviceName: IntegrationService!
  ): IntegrationSetting
  """
  Requires permission `settings:integration:read`.
  
  Lists the organization's integrations, highest priority first and then by service name. Needs settings:integration:read.
  """
  integrationSettings: [IntegrationSetting!]!
  """
  Requires permission `settings:integration:read`.
  
  Returns integration totals for the organization: how many are set up, switched on and valid, with the status of each and when they last changed. Requires permission to read integrations.
  """
  integrationsSummary: IntegrationSummary!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:create`, `inventory:stock_level:list`, `inventory:stock_level:read` or `inventory:stock_transfer:create`.
  
  Lists stock rows: each variant's stock and reorder settings per warehouse, with the row ID, SKU and warehouse, and quantities on hand, reserved and available. Search by SKU, product or warehouse name; filtered, sorted and paged. Use inventoriesCount for the total. Needs the stock level read or list permission, or the stock adjustment or stock transfer create permission.
  """
  inventories(
    """
    Optional filters: warehouse, product, variant, search text, batch, serial number, quantity range, stock status flags such as low, out of or over stock, and date ranges.
    """
    filter: InventoryFilterInput
    """
    The field to sort by, such as quantity, available quantity, reserved quantity, last counted time, update time, total value, or product or variant name.
    """
    orderBy: InventoryOrderByInput
    """How many rows to skip. Defaults to 0."""
    skip: Int = 0
    """How many rows to return. Defaults to 50 and is capped at 100."""
    take: Int = 50
  ): PaginatedInventories!
  """
  Requires at least one of the permissions `inventory:stock_level:list` or `inventory:stock_level:read`.
  
  Returns how many inventory rows match the same filter as inventories, ignoring paging, for a pager. Needs the stock level read or list permission.
  """
  inventoriesCount(
    """Optional filters. The same ones as inventories."""
    filter: InventoryFilterInput
  ): Int!
  """
  Requires permission `inventory:stock_level:read`.
  
  Returns one stock line (one product variant in one warehouse) by ID, or null when it does not exist in your organization. Needs the stock level read permission.
  """
  inventory(
    """The ID of the inventory record."""
    id: ID!
  ): Inventory
  """
  Requires permission `analytics:organization:read`.
  
  Inventory analytics for the whole organization or one warehouse: total products and value, low-stock, out-of-stock and excess-stock counts, stock by category, top-moving products, turnover and warehouse utilization. Org-wide stock valuation: needs the organization analytics read permission.
  """
  inventoryAnalytics(
    """Only this warehouse. Omit for all warehouses."""
    warehouseId: String
  ): InventoryAnalytics!
  """
  Requires an authenticated session.
  
  Inventory analytics for a date range: valuation, stock-outs, dead stock, oversold items, shrinkage, expiring batches, the mix of movements and the turnover ratio. The range is required and limited to 400 days.
  """
  inventoryAnalyticsV2(
    """The date range and optional warehouse to report on."""
    range: InventoryRangeInput!
  ): InventoryAnalyticsV2!
  """
  Requires at least one of the permissions `inventory:stock_level:read` or `sales:sales_order:allocate`.
  
  Lists the reservations held against one stock line: which orders have set aside how much of its quantity. Needs the stock level read or the sales order allocate permission.
  """
  inventoryReservations(
    """The ID of the inventory record."""
    inventoryId: ID!
  ): [InventoryReservationInfo!]!
  """
  Requires permission `inventory:stock_level:read`.
  
  Returns headline stock figures: total products and variants, total and available quantity, and the number of low-stock, out-of-stock and overstock items. Pass `warehouseId` or `productId` to narrow it. Needs the stock level read permission.
  """
  inventorySummary(
    """Only this product."""
    productId: ID
    """Only this warehouse."""
    warehouseId: ID
  ): InventorySummary!
  """
  Requires at least one of the permissions `payments:invoice:read` or `purchase:purchase_invoice:read`.
  
  Returns one invoice by ID. A user restricted to their own customers cannot open an invoice outside that book.
  """
  invoice(
    """The ID of the invoice."""
    id: ID!
  ): Invoice!
  """
  Requires at least one of the permissions `payments:invoice:read` or `purchase:purchase_invoice:read`.
  
  Lists the audit trail of one invoice: who changed it, when, and what changed.
  """
  invoiceAuditLogs(
    """The ID of the invoice."""
    invoiceId: ID!
  ): [AuditLog!]!
  """
  Requires at least one of the permissions `payments:invoice:read` or `purchase:purchase_invoice:read`.
  
  Shows what `cancelInvoice` would do without changing anything: whether it can be cancelled, the blockers that would stop it, the payment allocations it would reverse, and the estimated credit note amount. `cancelInvoice` acts on the same reading and is rejected if its outcome would differ.
  """
  invoiceCancellationPreview(
    """The ID of the invoice."""
    id: ID!
  ): InvoiceCancellationPreview!
  """
  Requires permission `sales:credit_note:create`.
  
  Returns how much of a sales invoice has already been credited and how much is left to credit: the same figures the credit note create and update limit enforces. Pass `excludeCreditNoteId` to leave out a credit note you are editing.
  """
  invoiceCreditHeadroom(
    """
    A credit note to leave out of the already-credited total, such as the one being edited.
    """
    excludeCreditNoteId: ID
    """The ID of the sales invoice."""
    invoiceId: ID!
  ): InvoiceCreditHeadroom!
  """
  Requires permission `purchase:debit_note:create`.
  
  Returns how much of a purchase invoice has already been debited and how much is left to debit: the same figures the debit note create and update limit enforces. Pass `excludeDebitNoteId` to leave out a debit note you are editing. Needs the debit notes feature on your plan.
  """
  invoiceDebitHeadroom(
    """
    A debit note to leave out of the already-debited total, such as the one being edited.
    """
    excludeDebitNoteId: ID
    """The ID of the purchase invoice."""
    invoiceId: ID!
  ): InvoiceDebitHeadroom!
  """
  Requires at least one of the permissions `payments:invoice:list` or `purchase:purchase_invoice:list`.
  
  Returns summary totals for the same filters as `invoices`, covering every matching invoice rather than one page.
  """
  invoiceListSummary(
    """The same filters as invoices. Totals cover every invoice that matches."""
    filter: InvoiceFilterInput
  ): InvoiceListSummary!
  """
  Requires at least one of the permissions `payments:invoice:list` or `purchase:purchase_invoice:list`.
  
  Lists invoices, sales and purchase, with optional filters and `skip` / `take` paging. A user restricted to their own customers sees only those customers' invoices, and purchase invoices need the purchase invoices feature on your plan. Sales invoices need the invoices list permission and purchase invoices the purchase invoices list permission; a caller holding one sees only that side.
  """
  invoices(
    """Optional filters."""
    filter: InvoiceFilterInput
    """Number of invoices to skip. Send with take for paging."""
    skip: Int
    """Number of invoices to return."""
    take: Int
  ): InvoiceConnection!
  """
  Public: no authentication required.
  
  Tells whether a subdomain is well formed and not yet taken by an organization. Needs no sign-in.
  """
  isSubdomainAvailable(
    """The subdomain to check."""
    subdomain: String!
  ): Boolean!
  """
  Requires permission `visits:journey-plan:manage`.
  
  Returns one sales rep's journey plan, the route of planned visits, for one day, or null when there is neither a saved plan nor an unplanned stop that day. Requires permission to manage journey plans.
  """
  journeyPlan(
    """The day of the plan."""
    planDate: DateTime!
    """The ID of the sales rep."""
    salesRepId: ID!
  ): JourneyPlan
  """
  Requires permission `visits:journey-plan:manage`.
  
  Returns journey plan totals over a date range: plans, planned stops and completed stops, counted over the whole range. Requires permission to manage journey plans.
  """
  journeyPlanSummary(
    """The first day of the range."""
    dateFrom: DateTime!
    """The last day of the range."""
    dateTo: DateTime!
    """The ID of the sales rep to total plans for. Omit it for every rep."""
    salesRepId: ID
  ): JourneyPlanListSummary!
  """
  Requires permission `visits:journey-plan:manage`.
  
  Lists sales reps' journey plans over a date range, optionally for one rep or filtered. Send skip and take to page, and use journeyPlansCount for the total. Requires permission to manage journey plans.
  """
  journeyPlans(
    """The first day of the range."""
    dateFrom: DateTime!
    """The last day of the range."""
    dateTo: DateTime!
    """Optional filters: search text, status and sort order."""
    filter: JourneyPlanListFilterInput
    """The ID of the sales rep to list plans for. Omit it for every rep."""
    salesRepId: ID
    """How many plans to skip. Omit skip and take to return the whole range."""
    skip: Int
    """How many plans to return."""
    take: Int
  ): [JourneyPlan!]!
  """
  Requires permission `visits:journey-plan:manage`.
  
  Returns how many journey plans match the same range, rep and filter as journeyPlans, ignoring paging, for a pager. Requires permission to manage journey plans.
  """
  journeyPlansCount(
    """The first day of the range."""
    dateFrom: DateTime!
    """The last day of the range."""
    dateTo: DateTime!
    """Optional filters. The same ones as journeyPlans."""
    filter: JourneyPlanListFilterInput
    """The ID of the sales rep to count plans for. Omit it for every rep."""
    salesRepId: ID
  ): Int!
  """
  Requires at least one of the permissions `settings:language:read` or `settings:tenant:read`.
  
  Returns one language. Requires permission to read language or tenant settings.
  """
  language(
    """The ID of the language."""
    id: String!
  ): Language!
  """
  Requires an authenticated session.
  
  Lists the platform's languages. Shared by every organization, and available to customer apps for a language picker.
  """
  languages: [Language!]!
  """
  Requires permission `sales:sales_order:read`.
  
  The customer's most recent order that is neither draft nor cancelled, with its lines, for repeating an order. Returns null when the customer has no qualifying order. Needs the sales order read permission.
  """
  lastSalesOrder(
    """The ID of the customer."""
    partnerId: ID!
  ): SalesOrder
  """
  Requires an authenticated session.
  
  Lists the organization's top-level menus with their active submenus.
  """
  mainMenus: [Menu!]!
  """
  Requires an authenticated session.
  
  Returns the signed-in user.
  """
  me: User!
  """
  Requires an authenticated session.
  
  Returns one menu with its active submenus and its parent. Fails if the menu does not exist.
  """
  menu(
    """The ID of the menu."""
    id: ID!
  ): Menu!
  """
  Requires an authenticated session.
  
  Lists the active submenus of one menu.
  """
  menuChildren(
    """The ID of the parent menu."""
    parentId: ID!
  ): [Menu!]!
  """
  Requires an authenticated session.
  
  Lists the organization's active menus as a tree, optionally filtered. Needs a signed-in user.
  """
  menus(
    """Optional filters: search text, active flag, menu type and parent menu."""
    filters: MenuFiltersInput
  ): [Menu!]!
  """
  Public: no authentication required.
  
  Returns the Android and iOS store links for a mobile app, so a person can share the one that suits a colleague. Needs no sign-in.
  """
  mobileAppStoreLinks(
    """The app's bundle identifier."""
    bundleId: String!
  ): MobileAppStoreLinks!
  """
  Public: no authentication required.
  
  Tells a mobile app whether it is up to date, can be updated, or must be updated, with the latest version, store link and release notes. Needs no sign-in. When no release is recorded or the version cannot be read, the app is reported as up to date.
  """
  mobileAppUpdateStatus(
    """The app's bundle identifier."""
    bundleId: String!
    """The version the app is running."""
    currentVersion: String!
    """The platform the app runs on."""
    platform: MobileAppPlatform!
  ): MobileAppUpdateStatus!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the buyer's single shared cart (or an empty cart if none exists). One cart per buyer/partner — not per delivery address; the address is chosen at placeOrder.
  """
  mobileCart: MobileCart!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the bill (subtotal + delivery + VAT + total) for the buyer's shared cart.
  """
  mobileCartBill(
    """
    the chosen live delivery option (mobileDeliveryOptions). Without it a live-quote store returns deliveryFee null and deliverySelectionRequired true.
    """
    deliveryOptionId: ID
    """
    Ignored. The printed-invoice fee was removed; kept so existing app builds that send it keep working.
    """
    includePrintedInvoice: Boolean = false
  ): MobileCartBill!
  """
  Public: no authentication required.
  
  Email-entry probe: true → route to OTP login (existing customer); false → route to the Sign Up / registration screen.
  """
  mobileCheckBuyerExists(
    """The details of the check buyer exists request."""
    input: CheckBuyerExistsInput!
  ): BuyerExistsResponse!
  """
  Requires a customer (portal or buyer app) session.
  
  P6: live delivery options for the buyer's cart to one of their addresses. FLAT stores return mode FLAT and no options (the bill carries the fee). LIVE_QUOTE stores return priced options whose id is passed back as deliveryOptionId on mobileCartBill and on placement; code NO_DELIVERY_OPTIONS means delivery is unavailable to this address.
  """
  mobileDeliveryOptions(
    """The ID of the address."""
    addressId: ID!
  ): CheckoutDeliveryOptions!
  """
  Public: no authentication required.
  
  Invited email + company for a team-invite token, for the buyer-app's locked prefill.
  """
  mobileInviteInfo(
    """The details of the mobile invite info request."""
    input: MobileInviteInfoInput!
  ): MobileInviteInfo!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns one of the buyer's SALES invoices in full — lines, bill breakdown, payments received and addresses — for the invoice-detail screen reached from Billing. Company-scoped: another partner's (or tenant's) invoice reads as not-found, and an unissued DRAFT / CANCELLED / VOIDED invoice is never returned.
  """
  mobileInvoice(
    """The ID of the invoice."""
    invoiceId: ID!
  ): MobileInvoice!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns a single order by id for the authenticated buyer. Used by the success and track screens for hard-reload hydration.
  """
  mobileOrder(
    """The ID of the order."""
    orderId: ID!
  ): MobileOrder!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the buyer's paginated order list. `status` is a plain Int: 0=All, 1=Active (not delivered/cancelled), 2=Cancelled. Optionally narrowed further by a placed-at date range and a search term (matches order number or an item's product name).
  """
  mobileOrders(
    """Cursor from the previous page. Omit for the first page."""
    cursor: String
    """Only records on or after this date."""
    dateFrom: DateTime
    """Only records on or before this date."""
    dateTo: DateTime
    "Maximum number of records to return."
    limit: Int = 20
    "Text to search for."
    search: String
    """Only orders with this status code. Defaults to 0, which means all."""
    status: Int = 0
  ): MobileOrderConnection!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns available payment methods for checkout. COD is always present; one ONLINE entry is added per eligible gateway (enabled, verified, and able to settle the store's currency). Zero eligible gateways means COD only.
  """
  mobilePaymentOptions: [MobilePaymentOption!]!
  """
  Requires a customer (portal or buyer app) session.
  
  the courier's live position for one of the buyer's company's shipments (an order shipment or its own return pickup). Null unless CustomerShipment.liveLocationAvailable (always null for an order shipment when the store's customer tracking is below full) — and still null while the carrier has no position. Another company's shipment is not found. Cached 15 s per shipment; poll no faster.
  """
  mobileShipmentLiveLocation(
    """The ID of the shipment."""
    shipmentId: ID!
  ): ShipmentLiveLocation
  """
  Requires a customer (portal or buyer app) session.
  
  The in-app tracking view for one of the buyer's company's shipments (an order shipment or its own return pickup): the shipment, its progress steps and when the carrier was last asked. Opening it asks the carrier (the answer is reused for 60 s); refresh: true asks again unless the last ask was under 30 s ago. A carrier failure sets updateDelayed and still returns the saved timeline. Another company's shipment is not found. Shaped by the store's customer tracking setting: progress-only hides the courier, number and link; order-status-only returns null for an order shipment (show no shipment section).
  """
  mobileTrackShipment(
    """
    True to fetch fresh tracking from the courier instead of using the stored status.
    """
    refresh: Boolean = false
    """The ID of the shipment."""
    shipmentId: ID!
  ): CustomerShipmentTracking
  """
  Requires a customer (portal or buyer app) session.
  
  Whether this buyer may manage their own addresses. The app reads `canAddAddress` to show or hide its add/edit controls; the server enforces the rule independently on every address mutation.
  """
  myAddressAccess: MobileAddressAccess!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the buyer's owned addresses.
  """
  myAddresses: [MyAddress!]!
  """
  Requires an authenticated session.
  
  Lists the signed-in user's recent sign-in events, newest first, with device and location.
  """
  myAuthLogs(
    """How many events to return. Defaults to 50."""
    limit: Int! = 50
  ): [AuthLogEntry!]!
  """
  Requires an authenticated session.
  
  Summarizes the signed-in user's last 100 sign-in events: successful and failed sign-ins, distinct devices and IP addresses, and the 10 most recent events.
  """
  myAuthStats: AuthStats!
  """
  Requires a customer (portal or buyer app) session.
  
  the caller's assigned ACTIVE branch addresses — drives the FE branch picker.
  """
  myBranches: [CustomerBranch!]!
  """
  Requires an authenticated session.
  
  Returns the signed-in user's own commission totals: this month's pending and paid, and lifetime earned, paid and outstanding.
  """
  myCommissionSummary: CommissionSummary!
  """
  Requires an authenticated session.
  
  Lists the signed-in user's own commission entries, optionally for one period or one status. Only their own entries are ever returned.
  """
  myCommissions(
    """The commission period to list, as YYYY-MM. Omit it for every period."""
    period: String
    """Only return entries in this status."""
    status: CommissionStatus
  ): [Commission!]!
  """
  Requires an authenticated session.
  
  The MCP apps (AI clients) you approved that still hold live access to your account in this organization.
  """
  myConnectedApps: [ConnectedApp!]!
  """
  Requires a customer (portal or buyer app) session.
  
  People on the buyer's account.
  """
  myContacts: [MobileContact!]!
  """
  Requires a customer (portal or buyer app) session.
  
  The buyer's current customer-tier status: effective tier, its discount %, this month's spend, and progress to the next tier. Tier resolution matches the charged price. Null when the organization has the customer-tiers module turned off.
  """
  myCustomerTier: MyCustomerTier
  """
  Requires an authenticated session.
  
  Lists the signed-in user's own notifications, newest first, one page at a time. A page holds at most 50.
  """
  myNotifications(
    """The cursor from the previous page. Omit it for the first page."""
    cursor: String
    """How many notifications to return. Defaults to 20 and is capped at 50."""
    take: Int = 20
  ): UserNotificationPage!
  """
  Requires an authenticated session.
  
  Lists every organization the signed-in person belongs to, matched by email, with their role and plan in each, for the organization switcher.
  """
  myOrganizations: [MyOrganization!]!
  """
  Requires an authenticated session.
  
  Lists the permissions the signed-in user holds in the current organization: exactly the set every permission check enforces (live role grants and granted direct grants).
  """
  myPermissions: [Permission!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the authenticated buyer profile (name, phone, address count).
  """
  myProfile: MobileBuyerProfile!
  """
  Requires a customer (portal or buyer app) session.
  
  Lists Expo push tokens registered for the authenticated buyer (newest first).
  """
  myPushTokens: [MobilePushToken!]!
  """
  Requires an authenticated session.
  
  Lists the customers an admin moved off the signed-in user in the last 30 days, so a rep can still see what they lost access to.
  """
  myReassignmentNotices: [ReassignmentNotice!]!
  """
  Requires an authenticated session.
  
  Lists the signed-in user's sessions with device, browser, location and last activity, and marks the current one.
  """
  mySessions: [SessionInfo!]!
  """
  Requires permission `notifications:push-token:manage`.
  
  Lists the push-notification tokens registered for the signed-in staff user. Requires permission to manage push tokens.
  """
  myStaffPushTokens: [MobilePushToken!]!
  """
  Requires an authenticated session.
  
  Whether the signed-in user is a tenant admin (the server's own rule).
  """
  myTenantAdminAccess: Boolean!
  """
  Requires an authenticated session.
  
  Lists the devices the signed-in user has trusted for sign-in, and marks the current one.
  """
  myTrustedDevices: [DeviceInfo!]!
  """
  Requires an authenticated session.
  
  Returns how many unread notifications the signed-in user has, for the bell badge.
  """
  myUnreadNotificationCount: Int!
  """
  Requires an authenticated session.
  
  Lists the signed-in rep's customer visits for one day: planned stops and unplanned visits, in route order. Only the caller's own visits are returned.
  """
  myVisits(
    """The day to list. Omit it for today."""
    date: DateTime
  ): [Visit!]!
  """
  Requires an authenticated session.
  
  Lists the signed-in rep's customer visits over a date range. The start must not be after the end, and the range is limited in length. Only the caller's own visits are returned.
  """
  myVisitsRange(
    """The first day of the range."""
    dateFrom: DateTime!
    """The last day of the range."""
    dateTo: DateTime!
  ): [Visit!]!
  """
  Requires at least one of the permissions `products:pricing:read`, `sales:quote:create` or `sales:sales_order:create`.
  
  Batch version of customerVariantPrice for the sales app's order pad. It prices up to 50 variant and unit requests in one call using the same pricing, and refuses a larger batch. Needs the pricing read permission, or the quote or sales order create permission. A customer outside your book is reported as not found.
  """
  orderPadVariantPrices(
    """ISO 4217 currency code to price in."""
    currency: String
    """
    The ID of the customer the prices are for. Optional: it only decides which discount schemes apply.
    """
    partnerId: String
    """The variants and units to price, at most 50."""
    requests: [OrderPadVariantPriceRequestInput!]!
  ): [CustomerVariantPrice!]!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns the live payment status for an order. Scoped to the authenticated buyer — another buyer's order returns not-found.
  """
  orderPaymentStatus(
    """The ID of the order."""
    orderId: ID!
  ): MobileOrderPaymentStatus!
  """
  Requires an authenticated session.
  
  Returns your own organization. The ID must be your own organization's; any other is refused. Its stats are filled in only for callers allowed to see organization-wide figures.
  """
  organization(
    """The ID of the organization."""
    id: String!
  ): Organization!
  """
  Requires an authenticated session.
  
  Returns your own organization by its subdomain. Another organization's subdomain reads as not found.
  """
  organizationBySubdomain(
    """Your organization's subdomain."""
    subdomain: String!
  ): Organization!
  """
  Requires the permissions `settings:organization:update` and `settings:system:update`.
  
  Counts the records a data reset would delete: products, variants, partners, quotes, sales and purchase orders, invoices, credit notes, payments, discount schemes, categories and brands. Needs the same permissions as resetOrganizationData: organization settings update and system settings update.
  """
  organizationDataSummary: ResetDataSummary!
  """
  Requires an authenticated session.
  
  The organization's default unit, used when a product has none. Returns null when no default is set or it points at a retired unit.
  """
  organizationDefaultUOM: UnitOfMeasure
  """
  Requires at least one of the permissions `settings:organization:read` or `settings:tenant:read`.
  
  Lists the hostnames that reach your organization's portal and their setup status. The platform hostname is always listed; it cannot be removed or made primary. Needs settings:organization:read, or settings:tenant:read.
  """
  organizationDomains: [OrganizationDomain!]!
  """
  Requires an authenticated session.
  
  Get organization localization settings
  """
  organizationExtension: OrganizationExtensionInfo
  """
  Requires an authenticated session.
  
  Returns company-wide figures for your own organization, such as revenue and document counts. Only callers allowed to see organization-wide figures can read them; any other organization ID is refused.
  """
  organizationStats(
    """Your own organization's ID."""
    organizationId: String!
  ): OrganizationStats!
  """
  Requires an authenticated session.
  
  Returns the organization's tax configuration, including its default sales and purchase tax groups, or null when none has been set.
  """
  organizationTaxConfig: OrganizationTaxConfiguration
  """
  Requires permission `payments:invoice:list`.
  
  Lists the unpaid sales invoices of one customer: the invoices a customer payment can be allocated to.
  """
  outstandingSalesInvoices(
    """The ID of the customer."""
    customerId: ID!
  ): [Invoice!]!
  """
  Requires at least one of the permissions `purchase:payment:create`, `purchase:purchase_invoice:list` or `purchase:purchase_invoice:read`.
  
  Lists the unpaid purchase invoices of one supplier: the invoices a supplier payment can be allocated to. Needs the purchase invoices list permission (or supplier payments create, to allocate a payment) and the purchase invoices feature on your plan.
  """
  outstandingSupplierInvoices(
    """The ID of the supplier."""
    supplierId: ID!
  ): [Invoice!]!
  """
  Requires permission `sales:sales_order:ship`.
  
  Packs the given lines and prices both packings with every enabled delivery partner, using the carrier's exact wording. It uses the same rule as checkout and the Ship dialog, and stores nothing. Requires permission to ship sales orders.
  """
  packingRatePreview(
    """
    The order lines, and either a saved address ID or a typed address, with optional warehouse.
    """
    input: PackingRatePreviewInput!
  ): PackingRatePreview!
  """
  Requires at least one of the permissions `customers:customer:list`, `customers:customer:read`, `payments:collection:create`, `payments:invoice:create`, `products:discount:update`, `purchase:debit_note:create`, `purchase:grn:create`, `purchase:payment:create`, `purchase:purchase_invoice:create`, `purchase:purchase_order:create`, `sales:credit_note:create`, `sales:quote:create`, `sales:sales_order:create`, `suppliers:supplier:list` or `suppliers:supplier:read`.
  
  Returns one partner by ID, including its money position, if the signed-in user may see it. A customer needs a customer read grant or a grant to raise a customer document; a supplier a supplier read grant or a grant to raise a purchase document.
  """
  partner(
    """The ID of the partner."""
    id: ID!
  ): Partner!
  """
  Requires permission `communications:consent:read`.
  
  Lists the recorded communication consent for the contacts of one customer. The customer must be in the caller's own book. Requires permission to read consent.
  """
  partnerConsent(
    """The ID of the customer."""
    partnerId: ID!
  ): PartnerConsentGql!
  """
  Requires permission `customers:customer_user:read`.
  
  Returns one person who can sign in for a customer company. Needs customers:customer_user:read.
  """
  partnerCustomerUser(
    """The ID of the customer company."""
    partnerId: ID!
    """The ID of the customer user."""
    userId: ID!
  ): PartnerCustomerUserDetail!
  """
  Requires permission `customers:customer_user:read`.
  
  Lists the people who can sign in to the buyer apps and portal for one customer company. Needs customers:customer_user:read.
  """
  partnerCustomerUsers(
    """The ID of the customer company."""
    partnerId: ID!
  ): [PartnerCustomerUser!]!
  """
  Requires permission `customers:customer_user:read`.
  
  One customer account's over-limit checkout requests, newest first, for the SELLER's console. The account's own approver decides from the app; a seller decides via partnerApproveOrderRequest / partnerDeclineOrderRequest. Pass status "PENDING" for the queue, omit it for full history.
  """
  partnerOrderApprovals(
    "Maximum number of records to return."
    limit: Int
    """The page to return, starting at 1."""
    page: Int
    """The ID of the partner."""
    partnerId: ID!
    """Only requests with this status."""
    status: String
  ): CustomerOrderApprovalConnection!
  """
  Requires at least one of the permissions `customers:customer:read` or `suppliers:supplier:read`.
  
  Returns summary counts of the organization's partners: all, active, customers, vendors, suppliers and recently added. Needs the customers read or suppliers read permission.
  """
  partnerStatistics: PartnerStatistics!
  """
  Requires at least one of the permissions `customers:customer:list`, `customers:customer:read`, `payments:collection:create`, `payments:invoice:create`, `products:discount:update`, `purchase:debit_note:create`, `purchase:grn:create`, `purchase:payment:create`, `purchase:purchase_invoice:create`, `purchase:purchase_order:create`, `sales:credit_note:create`, `sales:quote:create`, `sales:sales_order:create`, `suppliers:supplier:list` or `suppliers:supplier:read`.
  
  Lists the partners the signed-in user may see, with an optional filter and sort. Pass skip and take to read one page, and use partnersCount for the total. Customers are listed for callers with a customer read grant or a grant to raise a customer document; suppliers for callers with a supplier read grant or a grant to raise a purchase document.
  """
  partners(
    """Narrows the partners returned."""
    filter: PartnerFilterInput
    """The number of partners to skip."""
    skip: Int
    """The order of the results."""
    sort: PartnerSortInput
    """
    The maximum number of partners to return. Leave out skip and take to get the whole set.
    """
    take: Int
  ): [Partner!]!
  """
  Requires at least one of the permissions `customers:customer:list`, `customers:customer:read`, `payments:collection:create`, `payments:invoice:create`, `products:discount:update`, `purchase:debit_note:create`, `purchase:grn:create`, `purchase:payment:create`, `purchase:purchase_invoice:create`, `purchase:purchase_order:create`, `sales:credit_note:create`, `sales:quote:create`, `sales:sales_order:create`, `suppliers:supplier:list` or `suppliers:supplier:read`.
  
  Returns how many partners match a filter, using the same filter and visibility as partners.
  """
  partnersCount(
    """Narrows the partners counted."""
    filter: PartnerFilterInput
  ): Int!
  """
  Requires at least one of the permissions `payments:payment:read` or `purchase:payment:read`.
  
  Returns one payment by ID. A user restricted to their own customers cannot open a payment outside that book. A collection needs the payments read permission; a supplier payment needs the supplier payments read permission.
  """
  payment(
    """The ID of the payment."""
    id: ID!
  ): Payment!
  """
  Requires at least one of the permissions `payments:payment:read` or `purchase:payment:read`.
  
  Lists the audit trail of one payment: who changed it, when, and what changed.
  """
  paymentAuditLogs(
    """The ID of the payment."""
    paymentId: ID!
  ): [AuditLog!]!
  """
  Requires permission `settings:integration:read`.
  
  Lists your organization's saved payment gateway configurations, one per provider.
  """
  paymentGatewayConfigs: [PaymentGatewayConfigGql!]!
  """
  Requires permission `settings:integration:read`.
  
  Lists the payment providers ARC supports, with the credential fields each one needs and the webhook URL to register in that provider's dashboard for your organization.
  """
  paymentGatewayProviders: [PaymentGatewayProviderInfo!]!
  """
  Requires at least one of the permissions `payments:payment:list` or `purchase:payment:list`.
  
  Returns summary totals for the same filters as `payments`, covering every matching payment rather than one page.
  """
  paymentListSummary(
    """The same filters as payments. Totals cover every payment that matches."""
    filter: PaymentFilterInput
  ): PaymentListSummary!
  """
  Requires the permissions `payments:invoice:list` and `payments:payment:list`.
  
  Returns the headline payment figures for the whole organization, the same numbers as `paymentsDashboard`. The `filter` argument is not used.
  """
  paymentSummary(
    """Not used: the summary always covers all payments."""
    supplierId: ID
  ): PaymentSummary!
  """
  Requires at least one of the permissions `customers:customer:read`, `payments:invoice:read`, `purchase:purchase_order:read`, `sales:quote:read`, `sales:sales_invoice:read`, `sales:sales_order:read`, `settings:tenant:read` or `suppliers:supplier:read`.
  
  The payment terms this organization offers. Returns the platform default set when the organization has not configured its own yet, so a picker is never empty.
  """
  paymentTerms(
    """Set to true to include inactive terms. Defaults to false."""
    includeInactive: Boolean
  ): [PaymentTerm!]!
  """
  Requires at least one of the permissions `payments:payment:list` or `purchase:payment:list`.
  
  Lists payments, collections and supplier payments, with optional filters and `skip` / `take` paging. Collections need the payments list permission and supplier payments the supplier payments list permission; a caller holding one sees only that side.
  """
  payments(
    """Optional filters."""
    filter: PaymentFilterInput
    """Number of payments to skip. Send with take for paging."""
    skip: Int
    """Number of payments to return."""
    take: Int
  ): PaymentConnection!
  """
  Requires the permissions `payments:invoice:list` and `payments:payment:list`.
  
  Returns the headline payment and invoice figures shown on the payments dashboard. Needs both the payment list and invoice list permissions.
  """
  paymentsDashboard: PaymentDashboard!
  """
  Requires a tenant administrator.
  
  Returns the customers waiting for approval grouped by owning sales rep, with a group for customers that have no rep. Tenant admins only.
  """
  pendingCustomersByRep: [PendingRepGroup!]!
  """
  Requires a tenant administrator.
  
  Returns how many customers are waiting for approval, plus the newest few. Light enough to poll. Tenant admins only.
  """
  pendingCustomersSummary: PendingCustomersSummary!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists returns that are still PENDING, waiting to be processed. Limited to the directions your list permissions allow.
  """
  pendingReturns: [ProductReturn!]!
  """
  Requires permission `analytics:sales:read`.
  
  Performance analytics for a period. Limited to the customers you may see.. Needs the sales analytics read permission.
  """
  performanceAnalytics(
    """The reporting period to analyse."""
    period: AnalyticsPeriod!
  ): PerformanceAnalytics!
  """
  Requires an authenticated session.
  
  Returns one permission by ID.
  """
  permission(
    """The ID of the permission."""
    id: ID!
  ): Permission!
  """
  Requires an authenticated session.
  
  Lists the permission groups, each with the grantable permissions of its module, for building a permission picker.
  """
  permissionGroups: [PermissionGroup!]!
  """
  Requires an authenticated session.
  
  Lists the permissions a tenant may grant, optionally narrowed by module or resource. Platform-reserved permissions are never listed.
  """
  permissions(
    """Only permissions in this module."""
    module: String
    """Only permissions on this resource."""
    resource: String
  ): [Permission!]!
  """
  Requires permission `settings:tenant:read`.
  
  Returns your organization's customer portal and buyer app settings: name, branding, which features are on, contact details and store links. Needs settings:tenant:read.
  """
  portalConfig: PortalConfigResponse!
  """
  Requires permission `settings:documents:read`.
  
  Render one document email template with sample data, using this org's brand, saved line-item columns, base currency and default language, applying an optional in-progress brand DRAFT. Persists nothing.
  """
  previewDocumentEmail(
    """Unsaved edits to preview. Omit to preview the saved version."""
    draft: DocumentEmailDraftInput
    """The language of the email, as a locale code."""
    locale: String
    """The kind of document the email is for."""
    type: String!
  ): DocumentEmailPreview!
  """
  Requires permission `settings:documents:read`.
  
  Render a preview PDF (base64) for the given document type, applying an optional in-progress DRAFT on top of the saved config. Persists nothing.
  """
  previewDocumentTemplate(
    """The kind of document."""
    documentType: String!
    """Unsaved edits to preview. Omit to preview the saved version."""
    draft: DocumentTemplateDraftInput
  ): String!
  """
  Requires an authenticated session.
  
  Generate a preview PDF with sample data to preview template styles
  """
  previewPdfTemplate(
    """The kind of document to preview."""
    documentType: String = "quote"
    """The template markup to preview. Omit to preview the saved one."""
    template: String = "professional"
  ): String!
  """
  Requires at least one of the permissions `analytics:organization:read` or `purchase:purchase_order:read`.
  
  Procure-to-pay (purchase side) analytics over a date range, limited to what your role may see: sales reps see their own records, admins see everything by default, and other staff see their team. Needs the purchase orders feature on your plan.. Needs the organization analytics read or purchase order read permission.
  """
  procureToPayAnalytics(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): ProcureToPayAnalytics!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:create`, `inventory:stock_transfer:create`, `payments:invoice:create`, `products:product:read`, `purchase:debit_note:create`, `purchase:grn:create`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:quote:create`, `sales:quote:update`, `sales:sales_invoice:create`, `sales:sales_order:create` or `sales:sales_order:update`.
  
  Returns one product with its variants. Fails if the product does not exist. Needs the products read permission, or permission to create or edit a document or stock form that picks products.
  """
  product(
    """The ID of the product."""
    id: String!
  ): Product!
  """
  Requires at least one of the permissions `audit:activity_log:read` or `products:product:read`.
  
  Returns the audit history of a product, newest first, with who made each change. Fails if the product does not exist. Needs the products read or the activity log read permission.
  """
  productActivityHistory(
    """The ID of the product."""
    productId: String!
  ): [ActivityLog!]!
  """
  Requires permission `products:product:read`.
  
  How many products and variants carry an attribute (or one value of it), and which product finders name it. Requires permission to read products.
  """
  productAttributeUsage(
    """The attribute, in any spelling."""
    attributeKey: String!
    """One value of it; absent asks about the whole attribute."""
    value: String
  ): ProductAttributeUsage!
  """
  Requires permission `products:product:read`.
  
  Lists the product attributes the organization's active variants carry, each value with how many variants carry it and the picture set for it. Requires permission to read products.
  """
  productAttributes: [ProductAttribute!]!
  """
  Requires permission `products:product:delete`.
  
  Read-only blast radius (variant count, open-document/cart references) for a bulk product delete — powers the confirmation dialog.
  """
  productBulkDeletePreview(
    """Which products to delete."""
    target: ProductBulkTargetInput!
  ): ProductBulkDeletePreview!
  """
  Requires permission `products:product:delete`.
  
  Poll a bulk delete operation's progress; terminal statuses are COMPLETED / COMPLETED_WITH_ERRORS / FAILED.
  """
  productBulkOperation(
    """The ID of the bulk product operation."""
    id: ID!
  ): ProductBulkOperation
  """
  Requires permission `products:product:read`.
  
  Returns a product's delivery flags: whether it ships in its own packaging and whether it is fragile. Requires permission to read products.
  """
  productDeliveryFlags(
    """The ID of the product."""
    productId: ID!
  ): ProductDeliveryFlags!
  """
  Requires at least one of the permissions `products:product:create` or `products:product:update`.
  
  Poll an enrichment job started by startProductEnrichment. Returns the suggestion once status is COMPLETED, or the reason once FAILED. Scoped to the caller’s organization. Needs the products create or update permission.
  """
  productEnrichmentJob(
    """The ID of the enrichment job."""
    jobId: ID!
  ): EnrichmentJob!
  """
  Requires permission `products:import:read`.
  
  Status/progress of one import.
  """
  productImport(
    """The ID of the import."""
    importId: String!
  ): ProductImportEntity!
  """
  Requires permission `products:import:preview`.
  
  The aggregated preview diff for the human approval gate.
  """
  productImportPreview(
    """The ID of the import."""
    importId: String!
  ): ProductImportPreview!
  """
  Requires permission `products:import:read`.
  
  Imports for the org, most recent first. `limit`/`offset` take one page; the history list reads `productImportsCount` for its pager.
  """
  productImports(
    "Maximum number of records to return."
    limit: Int
    "Number of records to skip before the first one returned."
    offset: Int
  ): [ProductImportEntity!]!
  """
  Requires permission `products:import:read`.
  
  How many imports the org has (the `productImports` pager total).
  """
  productImportsCount: Int!
  """
  Requires permission `products:product:read`.
  
  Returns up to 20 upsell, cross-sell or substitute suggestions for a set of products, for example a customer's purchase history. Each suggested product appears once, deleted products are left out, and the list is empty when nothing is set up. Needs the products read permission.
  """
  productRelationSuggestions(
    """The IDs of the source products to find suggestions for."""
    productIds: [String!]!
  ): [ProductRelationSuggestion!]!
  """
  Requires permission `sales:shipment:read`.
  
  Lists the courier pickups booked for one customer return. A user restricted to their own customers sees only returns they can open. Needs the shipment read permission.
  """
  productReturnShipments(
    """The ID of the product return."""
    productReturnId: ID!
  ): [ShipmentGql!]!
  """
  Requires permission `products:product:read`.
  
  Returns product counts for your organization, such as total, active, inactive, out-of-stock and low-stock products, products per category, inventory value and recently added products. Needs the products read permission.
  """
  productSummary: ProductSummary!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:create`, `inventory:stock_transfer:create`, `payments:invoice:create`, `products:product:read`, `purchase:debit_note:create`, `purchase:grn:create`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:quote:create`, `sales:quote:update`, `sales:sales_invoice:create`, `sales:sales_order:create` or `sales:sales_order:update`.
  
  Returns one variant with its stock figures. Fails if the variant does not exist. Needs the products read permission, or permission to create or edit a document or stock form that picks products.
  """
  productVariant(
    """The ID of the variant."""
    id: ID!
  ): ProductVariant!
  """
  Requires permission `products:product:delete`.
  
  Read-only blast radius (default-variant/last-variant checks, open-document/cart references) for a bulk variant delete.
  """
  productVariantBulkDeletePreview(
    """The details of the product variant bulk delete request."""
    input: ProductVariantBulkDeleteInput!
  ): ProductBulkDeletePreview!
  """
  Requires permission `products:product:read`.
  
  Lists the variants of a product. Fails if the product does not exist. Needs the products read permission.
  """
  productVariants(
    """The ID of the product."""
    productId: ID!
  ): [ProductVariant!]!
  """
  Requires permission `products:product:read`.
  
  Lists active variants that have no weight or no size of their own, one page at a time. Requires permission to read products.
  """
  productVariantsMissingShippingData(
    """
    Only return variants matching this text. Only the first 100 characters are used.
    """
    search: String
    """How many variants to skip. Defaults to 0."""
    skip: Int
    """How many variants to return, from 1 to 200. Defaults to 50."""
    take: Int
  ): ProductVariantShippingDataGapPage!
  """
  Requires permission `products:product:read`.
  
  Returns how many active variants have no weight or no size of their own, using the same rule and total as productVariantsMissingShippingData. Requires permission to read products.
  """
  productVariantsMissingShippingDataCount: Int!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:create`, `inventory:stock_transfer:create`, `payments:invoice:create`, `products:discount:create`, `products:product:list`, `products:product:read`, `purchase:debit_note:create`, `purchase:grn:create`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:quote:create`, `sales:quote:update`, `sales:sales_invoice:create`, `sales:sales_order:create`, `sales:sales_order:update` or `storefront:storefront:update`.
  
  Returns a page of the products of your organization with a total count. Filter by search text, category, brand, status, price, tags and stock, and sort by name, SKU, price or date. Pages hold at most 100 products. Needs the products read or list permission, or permission to create or edit a document, stock form, discount scheme or storefront that picks products.
  """
  products(
    """The cursor from the previous page. Omit it for the first page."""
    cursor: String
    """
    Optional filters: search text, category, brand, status, price range, tags, stock and last-updated date.
    """
    filter: ProductFilterInput
    """How many products to return, at most 100. Defaults to 20."""
    limit: Int! = 20
    """
    Set to true to load only the fields a catalog sync needs and skip the heavy per-variant details. Defaults to false.
    """
    lite: Boolean = false
    """How many products to skip, as an alternative to a cursor."""
    skip: Int
    """
    Set to true to skip counting all matching products, which makes large pages faster. Defaults to false.
    """
    skipTotalCount: Boolean = false
    """The field and direction to sort by."""
    sort: ProductSortInput
  ): ProductConnection!
  """
  Public: no authentication required.
  
  Returns an organization's logo, favicon, company name and primary color for its sign-in page. Needs no sign-in. Without an organization, or if it cannot be read, it returns default branding.
  """
  publicBrandingSettings(
    """The ID of the organization."""
    organizationId: String
  ): PublicBrandingSettings!
  """
  Public: no authentication required.
  
  Lists a seller's brands for the public storefront. Needs no sign-in. An unknown subdomain gives an empty list.
  """
  publicBrands(
    """Only brands with products in this category or beneath it."""
    categoryId: ID
    """The seller's storefront subdomain."""
    subdomain: String!
  ): [CustomerBrand!]!
  """
  Public: no authentication required.
  
  Returns a seller's category tree for the public storefront. Needs no sign-in. An unknown subdomain gives an empty list.
  """
  publicCategories(
    """The seller's storefront subdomain."""
    subdomain: String!
  ): [CustomerCategory!]!
  """
  Public: no authentication required.
  
  Returns a seller's public portal settings for its storefront login page. Needs no sign-in. Returns null for an unknown subdomain.
  """
  publicPortalConfig(
    """The seller's storefront subdomain."""
    subdomain: String!
  ): PublicPortalConfig
  """
  Public: no authentication required.
  
  Returns one active product of a seller for the public storefront. Needs no sign-in. An unknown subdomain is refused with an "Organization not found" error.
  """
  publicProductDetail(
    """The ID of the product."""
    productId: ID!
    """The seller's storefront subdomain."""
    subdomain: String!
  ): CustomerProductDetail!
  """
  Public: no authentication required.
  
  Lists a seller's active products for the public storefront, one page at a time. Needs no sign-in. An unknown subdomain gives an empty list.
  """
  publicProducts(
    """Search text, filters, sort order and paging for the list."""
    filter: CustomerProductFilterInput
    """The seller's storefront subdomain."""
    subdomain: String!
  ): CustomerProductConnection!
  """
  Public: no authentication required.
  
  One page of the storefront buyers see on the customer portal: the LIVE published theme (never the draft), or the basic default theme when the store has published nothing, with the catalog records of the data sections in the part read. `page` picks it (HOME by default); `record` names the category, brand or product whose template is wanted; `slug` names a custom page. Null when no store answers on this host (no auth).
  """
  publicStorefrontPage(
    """The page to return."""
    page: StorefrontPageKind = HOME
    """The slug of one record to show on the page."""
    record: String
    """The slug of the page or record."""
    slug: String
    """The tenant's storefront subdomain."""
    subdomain: String!
  ): PublicStorefrontPage
  """
  Requires permission `analytics:organization:read`.
  
  Purchase analytics for a period: total purchases and orders, average order value, growth, orders by status, purchases by period and category, and top suppliers and products. Needs the purchase orders feature on your plan. Org-wide purchase spend: needs the organization analytics read permission.
  """
  purchaseAnalytics(
    """The period to report on."""
    period: AnalyticsPeriod!
  ): PurchaseAnalytics!
  """
  Requires at least one of the permissions `purchase:debit_note:create`, `purchase:grn:create`, `purchase:grn:read`, `purchase:purchase_invoice:create` or `purchase:purchase_order:read`.
  
  Returns one purchase order by ID. Needs the purchase order read permission, or a permission to read or raise a document against it (GRN read or create, debit note create, purchase invoice create), and the purchase orders feature on your plan.
  """
  purchaseOrder(
    """The ID of the purchase order."""
    id: ID!
  ): PurchaseOrder!
  """
  Requires permission `purchase:purchase_order:read`.
  
  Lists the audit trail of one purchase order: who changed it, when, and what changed. Needs the purchase order read permission and the purchase orders feature on your plan.
  """
  purchaseOrderAuditLogs(
    """The ID of the purchase order."""
    purchaseOrderId: ID!
  ): [AuditLog!]!
  """
  Requires permission `purchase:purchase_order:create`.
  
  Builds a suggested purchase order from a sales order, to buy what that order needs. Nothing is saved. A cancelled sales order is refused. The suggested supplier for each variant is the most recently touched preferred, active vendor product whose supplier is an active supplier of your organization. Needs the purchase order create permission and the purchase orders feature on your plan.
  """
  purchaseOrderDraftFromSalesOrder(
    """The ID of the sales order to build the draft from."""
    salesOrderId: ID!
  ): PurchaseOrderDraftFromSalesOrder!
  """
  Requires at least one of the permissions `purchase:purchase_order:list` or `purchase:purchase_order:read`.
  
  Returns summary figures for purchase orders: counts and values by status (draft, pending, approved, received) and the most recent orders. Needs the purchase order read or list permission and the purchase orders feature on your plan.
  """
  purchaseOrderSummary(
    """Only this supplier."""
    supplierId: ID
  ): PurchaseOrderSummary!
  """
  Requires at least one of the permissions `purchase:grn:create`, `purchase:purchase_order:list` or `purchase:purchase_order:read`.
  
  Lists purchase orders with optional filters and paging. Needs the purchase order read or list permission (or GRN create, to pick the order a receipt is raised against) and the purchase orders feature on your plan.
  """
  purchaseOrders(
    """Filter criteria for purchase order records. Omit to match all."""
    filters: PurchaseOrderFiltersInput
    "Number of records to skip. Send with take to page through results."
    skip: Int
    "Number of records to return."
    take: Int
  ): [PurchaseOrder!]!
  """
  Requires at least one of the permissions `purchase:grn:create`, `purchase:purchase_order:list` or `purchase:purchase_order:read`.
  
  Returns how many purchase orders match the filters, without loading them. Needs the purchase order read or list permission (or GRN create) and the purchase orders feature on your plan.
  """
  purchaseOrdersCount(
    """Filter criteria for purchase order records. Omit to match all."""
    filters: PurchaseOrderFiltersInput
  ): Int!
  """
  Requires at least one of the permissions `purchase:purchase_invoice:list` or `purchase:purchase_invoice:read`.
  
  Returns the summary of unpaid purchase invoices: total outstanding, current and overdue amounts, average days outstanding, aging, and the suppliers owed. Needs the purchase invoices list or read permission and the purchase invoices feature on your plan.
  """
  purchaseOutstandingSummary: OutstandingSummary!
  """
  Requires permission `settings:tenant:read`.
  
  Lists, for each push channel, how a notification type is rolled out and which types an admin may turn off. Needs settings:tenant:read.
  """
  pushEventControls: PushEventControls!
  """
  Requires permission `sales:quote:read`.
  
  Fetch one quote by id, with its lines and customer. Returns an error if the quote does not exist or is outside the caller's customer scope.
  """
  quote(
    """The ID of the quote."""
    id: ID!
  ): Quote!
  """
  Requires permission `sales:quote:read`.
  
  Audit trail for one quote: every recorded change with who made it and when. Scoped to the caller's customer visibility.
  """
  quoteAuditLogs(
    """The ID of the quote."""
    quoteId: ID!
  ): [AuditLog!]!
  """
  Requires permission `sales:quote:read`.
  
  Email engagement for one quote: sends, opens, clicks and replies.
  """
  quoteEmailAnalytics(
    """The ID of the quote."""
    quoteId: ID!
  ): QuoteEmailAnalytics!
  """
  Requires permission `sales:quote:read`.
  
  The email conversation for one quote: every message sent and received.
  """
  quoteEmailThread(
    """The ID of the quote."""
    quoteId: ID!
  ): [QuoteEmailActivity!]!
  """
  Requires permission `sales:quote:read`.
  
  Totals for the quote list KPI strip. Takes the same filter as quotesPaginated and totals the whole filtered set in the organization's base currency.
  """
  quoteListSummary(
    """
    The same filters as quotesPaginated. Totals cover every quote that matches.
    """
    filter: QuoteFilterInput
  ): QuoteListSummary!
  """
  Requires permission `analytics:sales:read`.
  
  Quote-to-cash analytics over a date range, limited to what your role may see: sales reps see their own records, admins see everything by default, and other staff see their team.. Needs the sales analytics read permission.
  """
  quoteToCashAnalytics(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): QuoteToCashAnalytics!
  """
  Requires permission `sales:quote:read`.
  
  List quotes for the organization, newest first. Filter by status, customer, dates or search text. Reps see only quotes for their own customers. Use quotesPaginated for large sets.
  """
  quotes(
    """Optional filters. Omit to list quotes the caller can see."""
    filter: QuoteFilterInput
  ): [Quote!]!
  """
  Requires permission `sales:quote:read`.
  
  Page through quotes with a cursor, or with limit and offset for numbered pages. Returns the page, the total count, whether more rows exist, and per-status counts for list headers.
  """
  quotesPaginated(
    """
    Filters and paging: send cursor for infinite scroll or offset for numbered pages, plus limit.
    """
    filter: QuoteFilterInput
  ): QuotesPaginatedResponse!
  """
  Requires permission `sales:quote:read`.
  
  Lean quote list for offline sync clients. Same filter and visibility as quotes, but returns only scalar quote and line fields. Relation fields such as the customer and creator are not populated.
  """
  quotesSync(
    """
    Optional filters. Send updatedAfter to fetch only quotes changed since the last sync.
    """
    filter: QuoteFilterInput
  ): [Quote!]!
  """
  Requires an authenticated session.
  
  Receivables analytics over a date range. Org-wide figures: needs the analytics:organization:read permission, so users limited to their own records are refused.
  """
  receivablesAnalytics(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): ReceivablesAnalytics!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists returns created in the last `days` days (default 7). Limited to the directions your list permissions allow.
  """
  recentReturns(
    """How many past days to include."""
    days: Int! = 7
  ): [ProductReturn!]!
  """
  Requires at least one of the permissions `settings:regional:read` or `settings:tenant:read`.
  
  Returns one region. Requires permission to read regional or tenant settings.
  """
  region(
    """The ID of the region."""
    id: String!
  ): Region!
  """
  Requires at least one of the permissions `settings:regional:read` or `settings:tenant:read`.
  
  Lists the platform's regions. They are shared by every organization. Requires permission to read regional or tenant settings.
  """
  regions: [Region!]!
  """
  Requires permission `commissions:commission:read`.
  
  Lists each sales rep's commission profile and default rate, for the caller's scope. Requires permission to read commissions.
  """
  repCommissionProfiles: [RepCommissionProfile!]!
  """
  Requires at least one of the permissions `purchase:debit_note:read` or `sales:credit_note:read`.
  
  Lists the audit trail of one return: who changed it, when, and what changed. Limited to the directions your read permissions allow.
  """
  returnAuditLogs(
    """The ID of the return."""
    returnId: String!
  ): [AuditLog!]!
  """
  Requires at least one of the permissions `purchase:debit_note:read` or `sales:credit_note:read`.
  
  Returns one return by ID. A return in a direction you cannot read is refused: sales returns need the credit note read permission and purchase returns the debit note read permission.
  """
  returnById(
    """The ID of the return."""
    id: String!
  ): ProductReturn!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists returns, sales and purchase, with optional filters and `skip` / `take` paging. You see only the directions your list permissions allow: a user who can list credit notes but not debit notes sees sales returns only.
  """
  returns(
    """Filter criteria for return records. Omit to match all."""
    filters: ReturnFilterInput
    "Number of records to skip. Send with take to page through results."
    skip: Int
    "Number of records to return."
    take: Int
  ): ReturnListResponse!
  """
  Requires an authenticated session.
  
  Returns analytics for a date range: the return rate, total return value, breakdowns by reason and by product, and the credit note value. The range is required and limited to 400 days.
  """
  returnsAnalytics(
    """The date range to report on."""
    range: AnalyticsRangeInput!
  ): ReturnsAnalytics!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists the returns of one customer or supplier. Limited to the directions your list permissions allow.
  """
  returnsByPartner(
    """The ID of the partner."""
    partnerId: String!
  ): [ProductReturn!]!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Lists the returns assigned to one warehouse. Limited to the directions your list permissions allow.
  """
  returnsByWarehouse(
    """The ID of the warehouse."""
    warehouseId: String!
  ): [ProductReturn!]!
  """
  Requires at least one of the permissions `purchase:debit_note:list` or `sales:credit_note:list`.
  
  Returns summary totals for the same filters as `returns`, covering every matching return rather than one page. Limited to the directions your list permissions allow.
  """
  returnsSummary(
    """Filter criteria for return records. Omit to match all."""
    filters: ReturnFilterInput
  ): ReturnListSummary!
  """
  Requires permission `payments:bank-account:update`.
  
  Returns the full, unmasked account number and IBAN of one bank account. This is the only way to read them, it needs permission to update bank accounts, and every reveal is audited.
  """
  revealBankAccountSecrets(
    """The ID of the bank account."""
    id: ID!
  ): BankAccountSecrets!
  """
  Requires at least one of the permissions `settings:role:read` or `users:user:update`.
  
  Returns one role of your organization by ID. Needs the roles read permission or the users update permission.
  """
  role(
    """The ID of the role."""
    id: ID!
  ): Role!
  """
  Requires at least one of the permissions `settings:permission:read` or `settings:role:read`.
  
  Lists the permissions granted to a role in your organization. Needs the roles read or permissions read permission.
  """
  rolePermissions(
    """The ID of the role."""
    roleId: ID!
  ): [Permission!]!
  """
  Requires at least one of the permissions `settings:role:list`, `settings:role:read`, `users:user:create` or `users:user:update`.
  
  Lists your organization's roles. Soft-deleted roles are left out unless includeDeleted is true. Needs the roles read or list permission, or the users create or update permission (the role picker on a user).
  """
  roles(
    """True to include soft-deleted roles. Leave out to exclude them."""
    includeDeleted: Boolean
  ): [Role!]!
  """
  Requires permission `analytics:sales:read`.
  
  Sales analytics for a period. Limited to the customers you may see.. Needs the sales analytics read permission.
  """
  salesAnalytics(
    """
    Does not change the figures: totals are always reported in the organization's base currency.
    """
    currency: String
    """The reporting period to analyse."""
    period: AnalyticsPeriod!
  ): SalesAnalytics!
  """
  Requires at least one of the permissions `payments:collection:create`, `sales:credit_note:create`, `sales:sales_order:deliver`, `sales:sales_order:read` or `sales:sales_order:ship`.
  
  Fetch one sales order by id with its lines. Linked purchase orders are included only for callers who may read purchase orders. Returns an error if the order is missing or outside the caller's customer scope. Needs the sales order read permission, or a permission to act on the order (ship, deliver, raise a credit note or record a collection against it).
  """
  salesOrder(
    """The ID of the sales order."""
    id: ID!
  ): SalesOrder!
  """
  Requires at least one of the permissions `sales:sales_order:allocate` or `sales:sales_order:read`.
  
  Warehouse allocation rows for one order. Each line can be split across warehouses, with an AUTO or MANUAL source and a RESERVED or BACKORDER status. Needs the sales order read or allocate permission.
  """
  salesOrderAllocations(
    """The ID of the sales order."""
    salesOrderId: ID!
  ): [SalesOrderItemAllocation!]!
  """
  Requires permission `sales:sales_order:read`.
  
  Audit trail for one sales order: every recorded change with who made it and when.
  """
  salesOrderAuditLogs(
    """The ID of the sales order."""
    salesOrderId: ID!
  ): [AuditLog!]!
  """
  Requires permission `sales:sales_order:read`.
  
  What the approval rules would decide if this sales order were confirmed now (pass, needs approval or blocked), checked without confirming or changing it. Returns null when no approval rule on confirming orders is enabled or the order cannot be confirmed from its status. Outcome NOT_CHECKED means another change was using the order's records; the rules are checked again on confirm. Reps see only orders for their own customers.
  """
  salesOrderConfirmPreview(
    """The ID of the sales order."""
    id: ID!
  ): SalesOrderConfirmPreview
  """
  Requires permission `sales:sales_order:read`.
  
  The email conversation for one order: every message sent and received.
  """
  salesOrderEmailThread(
    """The ID of the sales order."""
    salesOrderId: ID!
  ): [SalesOrderEmailActivity!]!
  """
  Requires permission `sales:shipment:read`.
  
  Lists the shipments booked for one sales order. A user restricted to their own customers sees only orders they can open. Needs the shipment read permission.
  """
  salesOrderShipments(
    """The ID of the sales order."""
    salesOrderId: ID!
  ): [ShipmentGql!]!
  """
  Requires at least one of the permissions `sales:sales_order:list` or `sales:sales_order:read`.
  
  Order counts and totals for the sales order list, scoped to the caller's customer visibility. Needs the sales order read or list permission.
  """
  salesOrderSummary: SalesOrderSummary!
  """
  Requires at least one of the permissions `sales:sales_order:list` or `sales:sales_order:read`.
  
  List sales orders for the organization, optionally filtered. Omit skip and take to return the whole filtered list, or send both for paging. Reps see only orders for their own customers. Needs the sales order read or list permission.
  """
  salesOrders(
    """Optional filters."""
    filters: SalesOrderFiltersInput
    """Number of orders to skip. Send with take for paging."""
    skip: Int
    """
    Number of orders to return. Omit skip and take to return the whole filtered list.
    """
    take: Int
  ): [SalesOrder!]!
  """
  Requires at least one of the permissions `sales:sales_order:list` or `sales:sales_order:read`.
  
  Count the sales orders that match the same filters as salesOrders, without returning the orders. Needs the sales order read or list permission.
  """
  salesOrdersCount(
    """The same filters as salesOrders."""
    filters: SalesOrderFiltersInput
  ): Int!
  """
  Requires permission `payments:invoice:list`.
  
  Returns what customers owe: outstanding and overdue receivables, with their aging. It covers the whole organization, or only the caller's own customers for a sales rep. Requires permission to list invoices.
  """
  salesOutstandingSummary: OutstandingSummary!
  """
  Requires permission `analytics:sales:read`.
  
  Sales performance analytics over a date range, limited to what your role may see: sales reps see their own records, admins see everything by default, and other staff see their team.. Needs the sales analytics read permission.
  """
  salesPerformanceAnalytics(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): SalesPerformanceAnalytics!
  """
  Requires at least one of the permissions `sales:quote:create`, `sales:quote:update`, `sales:sales_order:create`, `sales:sales_order:ship`, `sales:sales_order:update` or `settings:tenant:read`.
  
  Returns the organization-wide sales policy: the highest discount a manual price override may imply and whether goods ship only after an invoice. Needs settings:tenant:read, or the permission to create or update quotes or sales orders, or to ship.
  """
  salesPolicy: SalesPolicy!
  """
  Requires permission `analytics:signals:read`.
  
  The sales signals worklist: every customer in your scope with an attention list, ranked by money at stake and urgency. Needs analytics:signals:read.
  """
  salesSignals(
    """Optional filter that narrows the customers evaluated."""
    filter: SalesSignalsFilterInput
    """Optional paging for the worklist."""
    page: SalesSignalsPageInput
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): SalesSignals!
  """
  Requires a customer (portal or buyer app) session.
  
  Returns typeahead suggestions.
  """
  searchSuggest(
    """The delivery address that decides what is in stock."""
    addressId: ID
    """The text the shopper typed."""
    q: String!
  ): SearchSuggestResponse!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:create`, `inventory:stock_transfer:create`, `payments:invoice:create`, `products:product:list`, `products:product:read`, `purchase:debit_note:create`, `purchase:grn:create`, `purchase:purchase_order:create`, `purchase:purchase_order:update`, `sales:quote:create`, `sales:quote:update`, `sales:sales_invoice:create`, `sales:sales_order:create` or `sales:sales_order:update`.
  
  Searches variants across the catalog. Search text matches SKU, name, barcode and product name; other filters cover product, brand, categories, status, stock and price range. Needs the products read or list permission, or permission to create or edit a document or stock form that picks products.
  """
  searchVariants(
    """The search text and filters, with paging."""
    filter: VariantFilterInput!
  ): VariantSearchResult!
  """
  Requires permission `communications:consent:read`.
  
  Tells whether a message on a channel for a purpose can be sent to a customer now, and the reason when it cannot. Marketing needs a recorded opt-in, marketing switched on for the organization, a customer not marked do-not-market, a time inside the send window and room under the caps; utility messages are not gated. Requires permission to read consent.
  """
  sendEligibility(
    """The channel the message would go on."""
    channel: ConsentChannel!
    """The ID of the customer."""
    partnerId: ID!
    """Whether the message is utility or marketing."""
    purpose: ConsentPurpose!
  ): SendEligibilityGql!
  """
  Requires permission `settings:integration:read`.
  
  Returns the organization's marketing send rules: whether marketing is on, the weekly cap per contact, the daily cap per customer and the daily send window. Requires permission to read integrations.
  """
  sendGovernorSettings: SendGovernorSettingsGql!
  """
  Requires permission `sales:shipment:read`.
  
  Returns one shipment by ID. A user restricted to their own customers cannot open a shipment whose order or return they cannot see. Needs the shipment read permission.
  """
  shipment(
    """The ID of the shipment."""
    id: ID!
  ): ShipmentGql!
  """
  Requires permission `sales:sales_order:ship`.
  
  Returns the phone number a booking falls back to: the shipping address phone, then the order's mobile, then the customer's contact. Give exactly one of `salesOrderId` or `productReturnId`. Null when there is none. Needs the delivery partners feature on your plan and the sales order ship permission.
  """
  shipmentCustomerPhone(
    """The ID of the product return, for a pickup."""
    productReturnId: ID
    """The ID of the sales order, for a delivery."""
    salesOrderId: ID
  ): String
  """
  Requires permission `sales:shipment:read`.
  
  Returns a short-lived download link for the shipment's courier label, or null when there is none. Needs the shipment read permission.
  """
  shipmentLabelUrl(
    """The ID of the shipment."""
    id: ID!
  ): String
  """
  Requires permission `sales:shipment:read`.
  
  Returns the courier's live position, asked of the carrier and cached for 15 seconds per shipment. Null unless the carrier supports live location and a courier is carrying the shipment (picked up or out for delivery), or when the carrier has no position yet. A carrier failure is returned as an error carrying the carrier's own words. Needs the delivery partners feature on your plan and the shipment read permission.
  """
  shipmentLiveLocation(
    """The ID of the shipment."""
    shipmentId: ID!
  ): ShipmentLiveLocation
  """
  Requires permission `sales:shipment:read`.
  
  The boxes of one shipment with what is in each (frozen at booking, or re-packed when that reproduces the parcels sent), each item's size per unit as known today, and a suggested arrangement for staff to pack by. Empty when the contents of the parcels are not known. No prices or costs.
  """
  shipmentPackedBoxes(
    """The ID of the shipment."""
    id: ID!
  ): [ShipmentPackedBox!]!
  """
  Requires permission `sales:shipment:read`.
  
  A signed link to the Packing List PDF of one shipment: one section per box (box n of N, box name and size, its items with SKU, name and quantity, a fragile marker and the box weight). No prices or costs.
  """
  shipmentPackingListUrl(
    """The ID of the shipment."""
    id: ID!
  ): String!
  """
  Requires permission `sales:shipment:read`.
  
  Returns a short-lived download link for the shipment's proof of delivery, or null when there is none. Needs the shipment read permission.
  """
  shipmentProofOfDeliveryUrl(
    """The ID of the shipment."""
    id: ID!
  ): String
  """
  Requires permission `sales:sales_order:ship`.
  
  Prices a shipment with every enabled delivery partner, at the seller's cost: either an order's outbound shipment (`salesOrderId`) or a return pickup from the customer to the warehouse (`productReturnId`, offered only by partners that handle returns). Give exactly one of the two; `lines` to ship apply to a sales order, not a return pickup. The result lists the rate options, the partners that could not quote and why, suggested parcels when boxes are packed for you, and the order's shipping charge and the customer's checkout choice. Needs the sales order ship permission.
  """
  shipmentRates(
    """The details of the shipment rates request."""
    input: ShipmentRatesInput!
  ): ShipmentRatesGql!
  """
  Requires permission `sales:shipment:list`.
  
  How many shipments each status group (Shipments list tab) holds under the filter — the filter's own statusGroup is ignored so every tab shows its count. Every group is listed. Rep-scoped like the list.
  """
  shipmentStatusGroupCounts(
    """Filter criteria for shipment list records. Omit to match all."""
    filter: ShipmentListFilterInput
  ): [ShipmentStatusGroupCount!]!
  """
  Requires permission `sales:shipment:read`.
  
  A signed link to the shipping sticker PDF of one shipment (our own box label: sender, recipient, order and shipment numbers, courier, AWB barcode, tracking QR, box n of N). One page per box.
  """
  shipmentStickerUrl(
    """The label layout to produce."""
    format: ShipmentStickerFormat
    """The ID of the shipment."""
    id: ID!
  ): String!
  """
  Requires permission `sales:shipment:list`.
  
  The tenant-wide Shipments list (outbound deliveries and return pickups), newest first. Filter by status group (tab), direction, a search over shipment / tracking / order / return number and customer name, a created-at window, and (staff with sales:sales_order:ship) whether the courier is paid. skip/take page it (take defaults to 25, at most 100). Rep-scoped: a shipment is listed when its order or return is visible. The cost columns (customer paid, courier charge, seller paid, courier payment) are filled only for callers with sales:sales_order:ship.
  """
  shipments(
    """Filter criteria for shipment list records. Omit to match all."""
    filter: ShipmentListFilterInput
    "Number of records to skip. Send with take to page through results."
    skip: Int
    "Number of records to return."
    take: Int
  ): ShipmentListPage!
  """
  Requires permission `sales:shipment:read`.
  
  A signed link to ONE shipping-sticker PDF covering many shipments (bulk print from the Shipments list, at most 100 ids). Same content as shipmentStickerUrl.
  """
  shipmentsStickersUrl(
    """The label layout to produce."""
    format: ShipmentStickerFormat
    """The IDs of the shipments."""
    ids: [ID!]!
  ): String!
  """
  Requires permission `sales:shipment:list`.
  
  The Shipments page summary strip under the list's filter (direction, search, created window; never the status tab or courier-payment filter): how many shipments each status group holds, and — only for staff with sales:sales_order:ship, else null — how many couriers are unpaid and the courier money per currency from shipments booked with cost tracking (courier charges, customer paid, seller paid, owed to and paid to couriers, recovery %). Amounts are decimal strings, never summed across currencies. Rep-scoped like the list.
  """
  shipmentsSummary(
    """Filter criteria for shipments summary records. Omit to match all."""
    filter: ShipmentsSummaryFilterInput
  ): ShipmentsSummary!
  """
  Requires at least one of the permissions `marketing:link:read`, `marketing:link:write` or `settings:integration:read`.
  
  Returns one short link of your organization, by its ID or its code. Fails if it does not exist. Needs the marketing links read or write permission, or the integration settings read permission.
  """
  shortUrl(
    """The ID, the short code or the custom alias of the short link."""
    idOrCode: String!
  ): ShortUrlEntity!
  """
  Requires at least one of the permissions `marketing:link:read`, `marketing:link:write` or `settings:integration:read`.
  
  Returns click statistics for one short link: total and unique clicks, and clicks by date, country, device and browser. Fails if the link does not exist. Needs the marketing links read or write permission, or the integration settings read permission.
  """
  shortUrlAnalytics(
    """The ID, the short code or the custom alias of the short link."""
    idOrCode: String!
  ): ShortUrlAnalytics!
  """
  Requires at least one of the permissions `marketing:link:read`, `marketing:link:write` or `settings:integration:read`.
  
  Lists the short links of your organization. Needs the marketing links read or write permission, or the integration settings read permission.
  """
  shortUrls: [ShortUrlEntity!]!
  """
  Requires at least one of the permissions `products:product:create` or `products:product:update`.
  
  Lists the organization's SKU patterns. Needs the products create or update permission.
  """
  skuPatterns: [SKUPattern!]!
  """
  Requires permission `sales:sales_order:create`.
  
  Returns live delivery options and prices for a draft sales order, before the order exists. Pass the chosen option's ID to createSalesOrder as its delivery option. Without delivery partners on the plan it answers that none are available, and the manual shipping amount stands. The customer must be in the caller's own book. Requires permission to create sales orders.
  """
  staffDeliveryOptions(
    """
    The customer, shipping address, order lines, and optional currency and warehouse.
    """
    input: StaffDeliveryOptionsInput!
  ): StaffDeliveryOptions!
  """
  Public: no authentication required.
  
  Get states/provinces for a country
  """
  states(
    """The two-letter ISO country code."""
    countryCode: String!
  ): [StateListItem!]!
  """
  Requires permission `inventory:stock_movement:read`.
  
  Returns one stock movement: the quantity moved in or out, its warehouse and the document behind it, or null when there is none. Needs the stock movement read permission.
  """
  stockMovement(
    """The ID of the stock movement."""
    id: ID!
  ): StockMovement
  """
  Requires at least one of the permissions `inventory:stock_adjustment:read`, `inventory:stock_movement:list`, `inventory:stock_movement:read` or `inventory:stock_transfer:read`.
  
  Lists stock movements across warehouses, filtered, sorted and paged. Use stockMovementsCount for the total. Needs the stock movement read or list permission, or the stock adjustment or stock transfer read permission.
  """
  stockMovements(
    """
    Optional filters: type, status, warehouse, product, variant, search text, batch, serial number, reference, and created or performed date ranges.
    """
    filter: StockMovementFilterInput
    """
    The field to sort by: creation time, performed time, movement number or quantity.
    """
    orderBy: StockMovementOrderByInput
    """How many movements to skip. Defaults to 0."""
    skip: Int = 0
    """How many movements to return. Defaults to 50 and is capped at 50,000."""
    take: Int = 50
  ): PaginatedStockMovements!
  """
  Requires at least one of the permissions `inventory:stock_adjustment:read`, `inventory:stock_movement:list`, `inventory:stock_movement:read` or `inventory:stock_transfer:read`.
  
  Returns how many stock movements match the same filter as stockMovements, ignoring paging, for a pager. Needs the stock movement read or list permission, or the stock adjustment or stock transfer read permission.
  """
  stockMovementsCount(
    """Optional filters. The same ones as stockMovements."""
    filter: StockMovementFilterInput
  ): Int!
  """
  Requires permission `storefront:storefront:read`.
  
  Live categories, brands or products for storefront sections, one result per request and in request order. PICKED lists this organization's active records for the picked ids, in the order picked; ids with no active record (deleted, inactive or another organization's) are left out. AUTO lists the automatic category grid; NEWEST, IN_CATEGORY and IN_BRAND list the newest active products. A request for products also needs products:product:read. Ids, names and pictures only, never a price or a stock level. Writes nothing.
  """
  storefrontCatalogRecords(
    """The details of the storefront catalog records request."""
    input: StorefrontCatalogRecordsInput!
  ): [StorefrontCatalogResult!]!
  """
  Requires permission `storefront:storefront:update`.
  
  Poll an edit job. Jobs expire an hour after their last update. A job whose server stopped before it finished reads FAILED (CANCELLED if a cancel was asked for) about a minute after its last update.
  """
  storefrontEditGenerationJob(
    """The edit job to read, as startStorefrontEditGeneration returned it."""
    jobId: ID!
  ): StorefrontEditJob!
  """
  Requires permission `storefront:storefront:read`.
  
  The pictures this organization uploaded for its storefront, newest first, a page at a time (24 by default, at most 60). Each is the relative serve path an image field stores. Writes nothing.
  """
  storefrontImages(
    """Pictures per page, 1 to 60; a larger number is read as 60."""
    limit: Int = 24
    """Which page, from 1. A page past the end has no pictures."""
    page: Int = 1
  ): StorefrontImagePage!
  """
  Requires permission `storefront:storefront:update`.
  
  Poll a page-generation job. Jobs expire an hour after their last update. A job whose server stopped before it finished reads FAILED (CANCELLED if a cancel was asked for) about a minute after its last update.
  """
  storefrontPageGenerationJob(
    """The ID of the page generation job."""
    jobId: ID!
  ): StorefrontPageJob!
  """
  Requires permission `storefront:storefront:update`.
  
  Poll a section-generation job. Jobs expire an hour after their last update. A job whose server stopped before it finished (a deploy, a crash) reads FAILED (CANCELLED if a cancel was asked for) about a minute after its last update.
  """
  storefrontSectionGenerationJob(
    """The ID of the section generation job."""
    jobId: ID!
  ): StorefrontSectionJob!
  """
  Requires permission `storefront:storefront:read`.
  
  The organization's storefront theme: its saved draft and the version buyers see.
  """
  storefrontTheme: StorefrontThemeState!
  """
  Restricted to platform staff.
  
  Platform only. What the Home CMS cutover would publish for each organization (or those named), with the importer's notes. Writes nothing.
  """
  storefrontThemeCutoverPreview(
    """Only these organizations. Omit for all."""
    organizationIds: [ID!]
  ): StorefrontCutoverReport!
  """
  Requires permission `storefront:storefront:read`.
  
  The storefront's published versions, newest first (the 50 most recent).
  """
  storefrontThemeVersions: [StorefrontThemeVersionSummary!]!
  """
  Public: no authentication required.
  
  Suggests up to three available subdomains based on an organization name. Needs no sign-in.
  """
  subdomainSuggestions(
    """The organization name to base suggestions on."""
    name: String!
  ): [String!]!
  """
  Requires at least one of the permissions `products:brand:create` or `products:brand:update`.
  
  Suggests an unused brand code for a brand name: the name upper-cased with punctuation dropped and spaces turned into underscores, numbered (_2, _3…) when a brand in your organization already uses it. Only a suggestion — creating the brand still refuses a code that is taken. Needs the brands create or update permission.
  """
  suggestBrandCode(
    """The brand name to build the code from."""
    name: String!
  ): String!
  """
  Requires permission `categories:category:create`.
  
  Suggests an unused category code for a category name: the name upper-cased with punctuation dropped and spaces turned into underscores, numbered (_2, _3…) when an active category in your organization already uses it. Only a suggestion — creating the category still refuses a code that is taken. Requires permission to create categories.
  """
  suggestCategoryCode(
    """The category name to build the code from."""
    name: String!
  ): String!
  """
  Requires an authenticated session.
  
  Supplier scorecard over a date range. Org-wide figures: needs the analytics:organization:read permission, so users limited to their own records are refused. Needs the purchase orders feature on your plan.
  """
  supplierScorecard(
    """The date range and, optionally, the visibility scope."""
    range: AnalyticsRangeInput!
  ): SupplierScorecard!
  """
  Requires at least one of the permissions `purchase:debit_note:create`, `purchase:grn:create`, `purchase:payment:create`, `purchase:purchase_invoice:create`, `purchase:purchase_order:create`, `suppliers:supplier:list` or `suppliers:supplier:read`.
  
  Lists the organization's active suppliers, each with the amount still owed to it (outstandingPayable). Needs a supplier read grant or a grant to raise a purchase document.
  """
  suppliers: [Partner!]!
  """
  Requires an authenticated session.
  
  Returns one tax group with its rates. Fails if it does not exist.
  """
  taxGroup(
    """The ID of the tax group."""
    id: ID!
  ): TaxGroup!
  """
  Requires permission `products:tax:read`.
  
  Returns tax-group counts for the whole organization. Needs the tax read permission.
  """
  taxGroupSummary: TaxGroupSummary!
  """
  Requires an authenticated session.
  
  Lists the organization's tax groups with their rates, optionally filtered and paged. Use taxGroupsCount for the total.
  """
  taxGroups(
    """Optional filters: sort, search text and active status."""
    filters: TaxGroupFiltersInput
    """How many tax groups to skip."""
    skip: Int
    """How many tax groups to return."""
    take: Int
  ): [TaxGroup!]!
  """
  Requires an authenticated session.
  
  Returns how many tax groups match the same filters as taxGroups, ignoring paging, for a pager.
  """
  taxGroupsCount(
    """Optional filters. The same ones as taxGroups."""
    filters: TaxGroupFiltersInput
  ): Int!
  """
  Requires an authenticated session.
  
  Returns one tax rate. Fails if it does not exist.
  """
  taxRate(
    """The ID of the tax rate."""
    id: ID!
  ): TaxRate!
  """
  Requires permission `products:tax:read`.
  
  Returns tax-rate counts for the whole organization and the values the list screen offers as filters. Needs the tax read permission.
  """
  taxRateSummary: TaxRateSummary!
  """
  Requires an authenticated session.
  
  Lists the organization's tax rates, optionally filtered and paged. Use taxRatesCount for the total.
  """
  taxRates(
    """
    Optional filters: sort, country, state, city, type, active, default and search text.
    """
    filters: TaxRateFiltersInput
    """How many tax rates to skip."""
    skip: Int
    """How many tax rates to return."""
    take: Int
  ): [TaxRate!]!
  """
  Requires an authenticated session.
  
  Returns the active tax rates for a place, taking the most specific match that exists: country with state, city and postal code, then each shorter combination, down to the country alone. Default rates come first.
  """
  taxRatesByLocation(
    """The city. Omit it to match at a broader level."""
    city: String
    """The country the tax applies in."""
    country: String!
    """The postal code. Omit it to match at a broader level."""
    postalCode: String
    """The state or region. Omit it to match at a broader level."""
    state: String
  ): [TaxRate!]!
  """
  Requires an authenticated session.
  
  Returns how many tax rates match the same filters as taxRates, ignoring paging, for a pager.
  """
  taxRatesCount(
    """Optional filters. The same ones as taxRates."""
    filters: TaxRateFiltersInput
  ): Int!
  """
  Requires at least one of the permissions `settings:email:read` or `settings:tenant:read`.
  
  Returns the organization's quote email statistics: emails sent, delivered, opened, clicked and replied to, with delivery, open, click and reply rates and the average response time. Rates are null until there is data. Requires permission to read email or tenant settings.
  """
  tenantEmailAnalytics: TenantEmailAnalytics!
  """
  Requires at least one of the permissions `settings:email:read` or `settings:tenant:read`.
  
  Returns the organization's quote email settings: the reply address, the sender name suffix and whether quotes may be emailed, or null when none were saved. Requires permission to read email or tenant settings.
  """
  tenantEmailSettings: TenantEmailSettings
  """
  Requires at least one of the permissions `settings:currency:read`, `settings:currency:update` or `settings:tenant:read`.
  
  Lists the organization's own dated exchange rates, and marks which are in force. Requires permission to read or update currency settings, or to read tenant settings.
  """
  tenantExchangeRates: TenantExchangeRateSettings!
  """
  Requires permission `settings:tenant:read`.
  
  Returns one setting by ID. A per-user setting is visible only to the user it belongs to; for anyone else it reads as not found. Needs settings:tenant:read.
  """
  tenantSetting(
    """The ID of the setting."""
    id: String!
  ): TenantSetting!
  """
  Requires permission `settings:tenant:read`.
  
  Returns one active setting by category and key, or null when there is none. Needs settings:tenant:read.
  """
  tenantSettingByKey(
    """The settings category. Not case sensitive."""
    category: String!
    """The setting's key within the category."""
    key: String!
  ): TenantSetting
  """
  Requires permission `settings:tenant:read`.
  
  Lists who changed a setting, when, and from what to what, newest first. A per-user setting's history is visible only to the user it belongs to; for anyone else the list is empty. Needs settings:tenant:read.
  """
  tenantSettingHistory(
    """The settings category. Not case sensitive."""
    category: String!
    """The setting's key within the category."""
    key: String!
    """The most entries to return. Defaults to 50."""
    limit: Int
  ): [SettingAudit!]!
  """
  Requires permission `settings:tenant:read`.
  
  Lists your organization's settings one page at a time, with optional filter, sort and category. Needs settings:tenant:read.
  """
  tenantSettings(
    """
    Filter, sort, paging and category for the list, and whether to include default settings.
    """
    input: GetTenantSettingsInput
  ): PaginatedSettingsResponse!
  """
  Requires permission `settings:tenant:read`.
  
  Lists the active settings of one category. Needs settings:tenant:read.
  """
  tenantSettingsByCategory(
    """
    The settings category, for example company or sales. Not case sensitive.
    """
    category: String!
  ): [TenantSetting!]!
  """
  Requires permission `settings:tenant:read`.
  
  Returns how many settings the organization has (all, active and customized), the settings grouped by category, and when any was last changed. Needs settings:tenant:read.
  """
  tenantSettingsSummary: SettingsSummary!
  """
  Requires permission `settings:controls:manage`.
  
  Shows what a saved control or an unsaved rule would decide for one existing record, condition by condition. Nothing is saved, recorded or sent for approval. Requires settings:controls:manage.
  """
  testControlOnRecord(
    """The control or rule, and the record to test it on."""
    input: TestControlOnRecordInput!
  ): ControlTestResultType!
  """
  Requires at least one of the permissions `settings:regional:read` or `settings:tenant:read`.
  
  Returns one timezone: its code, UTC offset and daylight-saving rules. Fails if the timezone does not exist. Requires permission to read regional or tenant settings.
  """
  timezone(
    """The ID of the timezone."""
    id: String!
  ): Timezone!
  """
  Requires at least one of the permissions `settings:regional:read` or `settings:tenant:read`.
  
  Lists every timezone the organization can choose, with its UTC offset, default first. Requires permission to read regional or tenant settings.
  """
  timezones: [Timezone!]!
  """
  Requires permission `sales:shipment:read`.
  
  The in-app tracking view: the shipment, its progress steps and when the carrier was last asked. Opening it asks the carrier (the answer is reused for 60 s); refresh: true asks again unless the last ask was under 10 s ago. A carrier failure sets carrierError (the carrier's own words) and still returns the saved timeline. Rep-scoped: an out-of-scope shipment is not found.
  """
  trackShipment(
    """
    True to fetch fresh tracking from the courier instead of using the stored status.
    """
    refresh: Boolean = false
    """The ID of the shipment."""
    shipmentId: ID!
  ): ShipmentTracking!
  """
  Requires permission `analytics:sales:read`.
  
  Trend analytics for a period. Limited to the customers you may see.. Needs the sales analytics read permission.
  """
  trendsAnalytics(
    """The reporting period to analyse."""
    period: AnalyticsPeriod!
  ): TrendsAnalytics!
  """
  Requires an authenticated session.
  
  Returns whether two-factor sign-in is on for the signed-in user and whether backup codes exist.
  """
  twoFactorStatus: TwoFactorStatusResponse!
  """
  Requires an authenticated session.
  
  Returns one user of your organization by ID. You may always read yourself; reading a colleague needs the users read permission.
  """
  user(
    """The ID of the user."""
    id: String!
  ): User!
  """
  Requires an authenticated session.
  
  Lists the permissions a user holds in your organization, combining direct grants and the permissions of their roles. Expired direct grants and grants through a deleted or inactive role are left out. Reading another user's needs the permissions read or users read permission.
  """
  userPermissions(
    """The ID of the user."""
    userId: ID!
  ): [Permission!]!
  """
  Requires an authenticated session.
  
  Returns the signed-in user's saved preferences, or null when they have never saved any. Available to customer apps too.
  """
  userPreferences: UserPreference
  """
  Requires permission `users:user:read`.
  
  Returns a user's reporting relationships in your organization. Needs users:user:read.
  """
  userRelationships(
    """The ID of the user."""
    userId: String!
  ): UserRelationshipSummary!
  """
  Requires permission `users:user:read`.
  
  Lists the roles assigned to a user, or an empty list if the user does not exist. A user in another organization is refused unless you hold the cross-organization user read permission. Needs users:user:read.
  """
  userRoles(
    """The ID of the user."""
    userId: String!
  ): [Role!]!
  """
  Requires permission `users:user:read`.
  
  Get all user IDs who report to the specified user
  """
  userSubordinates(
    """True to include indirect reports, not just direct ones."""
    recursive: Boolean = true
    """Only subordinates of these user types."""
    types: [String!]
    """The ID of the manager."""
    userId: String!
  ): [String!]!
  """
  Requires at least one of the permissions `audit:activity_log:read`, `customers:customer:read`, `sales:quote:create`, `settings:user:list`, `settings:user:read`, `users:user:read` or `visits:journey-plan:manage`.
  
  Lists the staff of your own organization, with optional filters. The organization always comes from the signed-in user; any organization ID you send is ignored. Needs the users read permission, or a permission whose screens name or pick colleagues (customers read, route planning, quote create, activity log read).
  """
  users(
    """Optional filters that narrow the users returned."""
    filters: UserFilters
    """
    Deprecated and ignored: the organization comes from the signed-in user. Kept optional so installed apps that still send it keep working.
    """
    organizationId: String
  ): [User!]!
  """
  Requires at least one of the permissions `sales:quote:create`, `sales:quote:update`, `settings:user:read` or `users:user:read`.
  
  Lists the users of your own organization, using the filters and paging in the input. Needs the users read permission, or the quote create or update permission (the quote owner picker).
  """
  usersFiltered(
    """Optional filters and paging options."""
    input: GetUsersInput
  ): PaginatedUsersResponse!
  """
  Requires at least one of the permissions `products:product:create` or `products:product:update`.
  
  Tells whether a SKU is free to use: true when no active variant of the organization has it. Needs the products create or update permission.
  """
  validateSKU(
    """
    The ID of a variant to leave out of the check, so a record's own SKU is not reported as taken.
    """
    excludeProductId: ID
    """The SKU to check."""
    sku: String!
  ): Boolean!
  """
  Requires permission `products:product:read`.
  
  Returns variant statistics for your organization: totals of active and inactive variants, the average number of variants per product, variants per product, and lists of top-selling and low-stock variants. Needs the products read permission.
  """
  variantAnalytics: VariantAnalytics!
  """
  Requires at least one of the permissions `inventory:stock_level:read`, `sales:quote:create`, `sales:sales_order:allocate` or `sales:sales_order:create`.
  
  For each variant given, returns the on-hand, reserved and available stock in each warehouse that holds it, including warehouses at zero. A variant with no stock record anywhere is untracked: it returns every active warehouse without quantities. Inactive and deleted warehouses are left out, and at most 200 variants are looked up. Needs the stock level read permission, or the quote create, sales order create or sales order allocate permission.
  """
  variantWarehouseStock(
    """The IDs of the variants to look up. Only the first 200 are used."""
    variantIds: [ID!]!
  ): [VariantWarehouseStock!]!
  """
  Requires at least one of the permissions `purchase:grn:read`, `purchase:purchase_order:read` or `suppliers:supplier:read`.
  
  Returns one vendor product: a supplier's SKU, cost, lead time and delivery record for a product. Fails when there is no such mapping. Needs the suppliers read, purchase order read or GRN read permission.
  """
  vendorProduct(
    """The ID of the vendor product mapping."""
    id: ID!
  ): VendorProduct!
  """
  Requires at least one of the permissions `purchase:grn:read`, `purchase:purchase_order:read` or `suppliers:supplier:read`.
  
  Lists vendor products: which supplier sells which product, with their costs and lead times, optionally filtered. Needs the suppliers read, purchase order read or GRN read permission.
  """
  vendorProducts(
    """
    Optional filters: supplier, product, variant, supplier SKU, search text, preferred and active flags, cost range, maximum lead time and minimum quality rating.
    """
    filter: VendorProductFilterInput
  ): [VendorProduct!]!
  """
  Requires at least one of the permissions `purchase:grn:read`, `purchase:purchase_order:read` or `suppliers:supplier:read`.
  
  Lists the vendors (suppliers) who supply one product variant, with each vendor's SKU, cost and lead time. Needs the suppliers read, purchase order read or GRN read permission.
  """
  vendorProductsByVariant(
    """The ID of the product."""
    productId: ID!
    """The ID of the variant."""
    variantId: ID!
  ): [VendorProduct!]!
  """
  Requires at least one of the permissions `purchase:grn:read`, `purchase:purchase_order:read` or `suppliers:supplier:read`.
  
  Lists every product one supplier sells, with its cost and lead time. Needs the suppliers read, purchase order read or GRN read permission.
  """
  vendorProductsByVendor(
    """The ID of the supplier."""
    vendorPartnerId: ID!
  ): [VendorProduct!]!
  """
  Requires at least one of the permissions `purchase:debit_note:create`, `purchase:grn:create`, `purchase:payment:create`, `purchase:purchase_invoice:create`, `purchase:purchase_order:create`, `suppliers:supplier:list` or `suppliers:supplier:read`.
  
  Lists the organization's active partners that carry the supplier role. Needs a supplier read grant or a grant to raise a purchase document.
  """
  vendors: [Partner!]!
  """
  Requires an authenticated session.
  
  Lists the signed-in user's notifications about one specific visit, such as a message from an admin on that stop.
  """
  visitMessages(
    """The ID of the visit."""
    visitId: ID!
  ): [UserNotification!]!
  """
  Requires an authenticated session.
  
  Returns one warehouse. Fails if it does not exist or has been deleted.
  """
  warehouse(
    """The ID of the warehouse."""
    id: ID!
  ): Warehouse!
  """
  Requires an authenticated session.
  
  Lists the organization's warehouses, optionally filtered by status, type or search text on name and code.
  """
  warehouses(
    """Optional filters: status, type and search text."""
    filter: WarehouseFilterInput
  ): [Warehouse!]!
  """
  Requires permission `settings:webhooks:read`.
  
  Lists webhook deliveries, newest first, optionally for one endpoint or one status. Returns 50 deliveries by default and at most 200. Requires permission to read webhooks.
  """
  webhookDeliveries(
    """
    Optional filters: endpoint, status (pending, succeeded or failed), page size and offset.
    """
    filter: WebhookDeliveryFilterInput
  ): [WebhookDelivery!]!
  """
  Requires permission `settings:webhooks:read`.
  
  Returns how many deliveries match the same endpoint and status filter as webhookDeliveries, ignoring paging, for a delivery-log pager. Requires permission to read webhooks.
  """
  webhookDeliveriesCount(
    """Optional filters. Only the endpoint and the status are used."""
    filter: WebhookDeliveryFilterInput
  ): Int!
  """
  Requires permission `settings:webhooks:read`.
  
  Lists the webhook endpoints of your organization. The signing secret is never returned here. Requires permission to read webhooks.
  """
  webhookEndpoints: [WebhookEndpoint!]!
  """
  Requires permission `settings:webhooks:read`.
  
  Lists the event types a webhook endpoint can subscribe to. Requires permission to read webhooks.
  """
  webhookEventTypes: [String!]!
  """
  Requires permission `settings:integration:read`.
  
  Lists the WhatsApp channels on the provider account, for the channel picker. A provider that does not use channels answers that it has none. Requires permission to read integrations.
  """
  whatsAppChannels(
    """
    The WhatsApp provider to use. Omit it to use the organization's enabled provider, else its most recently edited one.
    """
    provider: WhatsAppProvider
  ): WhatsAppChannelsResultGql!
  """
  Requires permission `settings:integration:read`.
  
  Returns the organization's WhatsApp configuration, or null when none exists. The API key is never returned. Requires permission to read integrations.
  """
  whatsAppConfig(
    """
    The WhatsApp provider to use. Omit it to use the organization's enabled provider, else its most recently edited one.
    """
    provider: WhatsAppProvider
  ): WhatsAppConfigGql
  """
  Requires permission `settings:integration:read`.
  
  Lists the organization's WhatsApp message log, newest first, across every provider so the history survives a provider switch. 25 entries by default. Requires permission to read integrations.
  """
  whatsAppMessageLogs(
    """Optional filter: how many entries to return."""
    filter: WhatsAppMessageLogFilterInput
  ): [WhatsAppMessageLogGql!]!
  """
  Requires permission `settings:integration:read`.
  
  Fetches the message templates from the WhatsApp provider account, live, so a trigger can be mapped to one. Requires permission to read integrations.
  """
  whatsAppTemplates(
    """
    The WhatsApp provider to use. Omit it to use the organization's enabled provider, else its most recently edited one.
    """
    provider: WhatsAppProvider
  ): WhatsAppTemplatesResultGql!
  """
  Requires permission `settings:integration:read`.
  
  Lists the WhatsApp triggers that can be switched on, such as the events that send a message. Requires permission to read integrations.
  """
  whatsAppTriggerCatalog: [WhatsAppTriggerDefinitionGql!]!
  """
  Requires permission `settings:integration:read`.
  
  Returns today's Zoho API usage as a JSON string: calls made, the daily limit, whether the 80 and 95 percent thresholds were reached, and the percent used. Requires permission to read integrations.
  """
  zohoApiUsage(
    """Deprecated — org comes from the JWT"""
    organizationId: String
  ): String
  """
  Requires permission `settings:integration:read`.
  
  Returns the Zoho connection of the organization as a JSON string: the Zoho organization name, plan tier, currency, whether it is active and when it last synced, or a not-connected marker. Requires permission to read integrations.
  """
  zohoConnectionStatus(
    """Deprecated — org comes from the JWT"""
    organizationId: String
  ): String
  """
  Requires permission `settings:integration:read`.
  
  Returns the state of the Zoho data migration as a JSON string, or a not-started marker when it has not run. Requires permission to read integrations.
  """
  zohoMigrationStatus: String
  """
  Requires permission `settings:integration:read`.
  
  Returns Zoho sync log entries, newest first, as a JSON string, optionally filtered by entity type and status. At most 100 entries per request. Use zohoSyncLogsCount for the total. Requires permission to read integrations.
  """
  zohoSyncLogs(
    """Only return entries for this entity type."""
    entityType: String
    """How many entries to return. Defaults to 50 and is capped at 100."""
    limit: Int = 50
    """How many entries to skip."""
    offset: Int
    """Deprecated — org comes from the JWT"""
    organizationId: String
    """Only return entries with this status."""
    status: String
  ): String
  """
  Requires permission `settings:integration:read`.
  
  Returns how many Zoho sync log entries match the same entity type and status as zohoSyncLogs, ignoring paging, for a pager. Requires permission to read integrations.
  """
  zohoSyncLogsCount(
    """Only count entries for this entity type."""
    entityType: String
    """Only count entries with this status."""
    status: String
  ): Int!
  """
  Requires permission `settings:integration:read`.
  
  Returns Zoho sync state as a JSON string: the count of mapped records per entity type and sync status, and each entity type's polling cursor with its last poll, last success, errors and whether the circuit is open. Requires permission to read integrations.
  """
  zohoSyncStatus(
    """Deprecated — org comes from the JWT"""
    organizationId: String
  ): String
}

"""A home section showing quick links."""
type QuickLinksSection {
  """The kind of home section."""
  kind: HomeSectionKind!
  """The links."""
  links: [HomeQuickLinkCell!]!
}

"""
A priced offer to a customer, valid until a set date. Converts to a sales order or invoice when accepted.
"""
type Quote {
  """The billing address, as text."""
  billingAddress: String
  """Competitor the quote was lost to, when known."""
  competitorName: String
  """The invoice this quote was converted to, if any."""
  convertedToInvoice: Invoice
  """When the quote was converted to an invoice."""
  convertedToInvoiceAt: DateTime
  """
  The ID of the invoice this quote was converted to. Null until converted.
  """
  convertedToInvoiceId: String
  """The sales order this quote was converted to, if any."""
  convertedToSalesOrder: SalesOrder
  """When the quote was converted to a sales order."""
  convertedToSalesOrderAt: DateTime
  """
  The ID of the sales order this quote was converted to. Null until converted.
  """
  convertedToSalesOrderId: String
  """When the record was created."""
  createdAt: DateTime!
  """Currency code of the document's amounts."""
  currency: String!
  """The customer the quote is for."""
  customer: Partner!
  """The customer's email address, as stored on the quote."""
  customerEmail: String
  """The ID of the customer the quote is for."""
  customerId: String!
  """The customer's mobile number, as stored on the quote."""
  customerMobile: String
  """The customer's name, as stored on the quote."""
  customerName: String
  """When the record was deleted. Null while it is active."""
  deletedAt: DateTime
  """The ID of the user who deleted the record."""
  deletedBy: String
  """Delivery instructions for the shipment."""
  deliveryInstructions: String
  """Total discount amount on the quote."""
  discountAmount: Float!
  """How the document-level discount is expressed: PERCENTAGE or AMOUNT."""
  discountType: String!
  """
  The document-level discount, as a percentage or an amount according to discountType.
  """
  discountValue: Float!
  """The ID of the user who created the record."""
  enteredBy: String!
  """The user who created the quote."""
  enterer: User!
  """
  Exchange rate between the document currency and the organization's base currency, when they differ.
  """
  exchangeRate: Float
  """Unique identifier of the record."""
  id: ID!
  """Notes for your team only; never shown to the customer."""
  internalNotes: String
  """The line items on the quote."""
  items: [QuoteItem!]!
  """Free-text detail recorded with a LOST close."""
  lossNotes: String
  """Why the quote was lost (closeQuote LOST) — tenant-defined label."""
  lossReason: String
  """When the quote was marked lost. Null otherwise."""
  lostAt: DateTime
  """Notes on the document, visible to the customer."""
  notes: String
  """The organization that owns the quote."""
  organization: Organization!
  """The ID of the organization (tenant) that owns the record."""
  organizationId: String!
  """The user who owns the quote."""
  ownership: DocumentOwnershipOutput
  """The payment terms agreed for the quote."""
  paymentTerms: String
  """How urgent the quote is: LOW, NORMAL, HIGH or URGENT."""
  priority: String
  """The date the quote was issued."""
  quoteDate: DateTime!
  """The human-readable quote number, unique within the organization."""
  quoteNumber: String!
  """Your own reference for the quote, such as a customer enquiry number."""
  reference: String
  """The shipping address, as text."""
  shippingAddress: String
  """Shipping charge on the quote."""
  shippingCost: Float!
  """
  Where the quote is in its lifecycle: DRAFT, SENT, ACCEPTED, REJECTED, EXPIRED or CONVERTED.
  """
  status: String!
  """Subtotal of the quote lines, as calculated by the server."""
  subtotal: Float!
  """Total tax on the quote."""
  taxAmount: Float!
  """
  Whether line prices include tax (INCLUSIVE) or tax is added on top (EXCLUSIVE).
  """
  taxCalculationMethod: String
  """The document-level tax rate, as a percentage."""
  taxRate: Float!
  """Terms and conditions printed on the quote."""
  terms: String
  """
  The quote total in the quote currency, as calculated and stored by the server.
  """
  totalAmount: Float!
  """When the record was last changed."""
  updatedAt: DateTime!
  """The ID of the user who last changed the record."""
  updatedBy: String!
  """
  The date until which the quote can be accepted. Null when it does not expire.
  """
  validUntil: DateTime
  """
  Optimistic-concurrency counter — pass back as expectedVersion on the next mutation.
  """
  version: Int!
  """The warehouse the quote is fulfilled from."""
  warehouse: Warehouse
  """The ID of the warehouse the quote is fulfilled from."""
  warehouseId: String
  """Why the quote was won (closeQuote WON) — tenant-defined label."""
  winReason: String
  """When the quote was marked won. Null otherwise."""
  wonAt: DateTime
}

"""
closeQuote outcome: WON records the win reason on an already-won quote; LOST moves the quote to REJECTED.
"""
enum QuoteCloseOutcome {
  """The customer did not buy."""
  LOST
  """The customer bought."""
  WON
}

"""
One email sent or received about a quote, with its delivery and engagement tracking.
"""
type QuoteEmailActivity {
  """Number of attachments on the email."""
  attachmentCount: Int!
  """The email body as HTML."""
  bodyHtml: String
  """A short plain-text preview of the body."""
  bodyPreview: String
  """
  The provider's reason for the bounce. Null when the email did not bounce.
  """
  bounceReason: String
  """
  Kind of bounce reported by the provider (for example hard or soft). Null when the email did not bounce.
  """
  bounceType: String
  """When the email bounced. Null when it did not."""
  bouncedAt: DateTime
  """Addresses copied on the email."""
  ccEmails: [String!]!
  """Total link clicks recorded across all recipients."""
  clickCount: Int!
  "When the record was created."
  createdAt: DateTime!
  """When the provider confirmed delivery. Null until delivered."""
  deliveredAt: DateTime
  """
  Whether the email was sent by you (OUTBOUND) or received from the customer (INBOUND).
  """
  direction: String!
  """When the email was first opened. Null if never opened."""
  firstOpenAt: DateTime
  """Sender address."""
  fromEmail: String!
  """Sender display name."""
  fromName: String
  """Whether the email carries at least one attachment."""
  hasAttachment: Boolean!
  "The unique ID of this record."
  id: ID!
  """
  The ID of the email this one replies to, used to thread the conversation.
  """
  inReplyToId: String
  """Whether this email is a reply to an earlier one."""
  isReply: Boolean!
  """When the email was last opened. Null if never opened."""
  lastOpenAt: DateTime
  """Total opens recorded."""
  openCount: Int!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """
  When the reply was processed into the document's activity. Null until processed.
  """
  processedAt: DateTime
  """The ID of the user who processed the reply. Null when unprocessed."""
  processedBy: String
  """The email provider that sent or received the message."""
  provider: String!
  """The provider's own ID for the message."""
  providerMessageId: String
  "The ID of the quote."
  quoteId: String!
  """When the email was sent or received."""
  sentAt: DateTime!
  """
  Delivery status of the email (for example SENT, DELIVERED, OPENED, BOUNCED).
  """
  status: String!
  """
  For a reply, the new text only, with the quoted earlier thread removed.
  """
  strippedTextReply: String
  """Subject line."""
  subject: String!
  """The email body as plain text."""
  textBody: String
  """Recipient address."""
  toEmail: String!
  """Recipient display name."""
  toName: String
  """Number of distinct recipients who opened the email."""
  uniqueOpens: Int!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""Email engagement for one quote."""
type QuoteEmailAnalytics {
  """Average hours the customer took to reply. Null with no replies."""
  avgResponseTimeHours: Float
  """Emails that bounced."""
  bounceCount: Int!
  """When the first reply arrived."""
  firstReplyAt: DateTime
  """When the first email was sent."""
  firstSentAt: DateTime
  """When the latest email was sent."""
  lastSentAt: DateTime
  """Total link clicks recorded."""
  totalClicks: Int!
  """Total opens recorded."""
  totalOpens: Int!
  """Replies received from the customer."""
  totalReplies: Int!
  """Emails sent about the quote."""
  totalSent: Int!
}

"""Filters for listing quotes."""
input QuoteFilterInput {
  """
  Access mode for hierarchical visibility. MINE = only my quotes, TEAM = my quotes + subordinates, ALL = all org quotes (admin only)
  """
  accessMode: AccessMode = MINE
  """Only quotes in this ISO 4217 currency."""
  currency: String
  """Cursor for pagination (quote ID)"""
  cursor: String
  """Only quotes for this customer."""
  customerId: String
  """Only quotes dated on or after this ISO 8601 date."""
  dateFrom: String
  """Only quotes dated on or before this ISO 8601 date."""
  dateTo: String
  """Number of quotes to return (max 100)"""
  limit: Int = 20
  """
  Rows to skip before the page (numbered paging). Takes precedence over cursor.
  """
  offset: Int
  """
  Case-insensitive text search over quote number, customer name, customer email, reference and the customer record's name.
  """
  search: String
  """Field to sort by. Defaults to UPDATED_AT."""
  sortBy: QuoteSortField = UPDATED_AT
  """Sort direction. Defaults to DESC."""
  sortOrder: SortOrder = DESC
  """Only quotes in these statuses."""
  status: [String!]
  """
  Only quotes changed strictly after this instant. Used for incremental sync; it can only narrow what the caller may see.
  """
  updatedAfter: String
  """Only quotes valid until on or after this ISO 8601 date."""
  validUntilFrom: String
  """Only quotes valid until on or before this ISO 8601 date."""
  validUntilTo: String
}

"""
A line on a quote: a product or variant, quantity, price, discount and tax.
"""
type QuoteItem {
  """When the record was created."""
  createdAt: DateTime!
  """When the record was deleted. Null while it is active."""
  deletedAt: DateTime
  """The ID of the user who deleted the record."""
  deletedBy: String
  """Free-text description of the line."""
  description: String
  """
  The line discount, as a percentage or an amount according to discountType.
  """
  discount: Float!
  """Total discount amount on the line."""
  discountAmount: Float!
  """How the line discount is expressed: PERCENTAGE or AMOUNT."""
  discountType: String!
  """The ID of the user who created the record."""
  enteredBy: String!
  """Unique identifier of the record."""
  id: ID!
  """
  Whose price this line carries: ENGINE, CLIENT, OVERRIDE, QUOTE_CONVERSION, IMPORT, or CONVERTED (the product's base price converted at the document rate). Null on older lines.
  """
  priceSource: String
  """The product on this line."""
  product: Product!
  """The ID of the product on this line."""
  productId: String!
  """The product name, as stored on the line."""
  productName: String!
  """The SKU of the variant, as stored on the line."""
  productSku: String
  """Quantity quoted, in the line's unit of measure."""
  quantity: Float!
  """The ID of the quote this line belongs to."""
  quoteId: String!
  """Pre-negotiated sale price from variant"""
  salePrice: Float
  """Position of the line on the quote."""
  sortOrder: Int!
  """Total tax on the line."""
  taxAmount: Float!
  """
  Tax applied to this line, as a list of { taxName, taxCode, taxType, rate, taxAmount }.
  """
  taxBreakdown: JSON
  """The ID of the tax group applied to this line."""
  taxGroupId: String
  """The tax rate applied to the line, as a percentage."""
  taxRate: Float!
  """The IDs of the tax rates applied to this line."""
  taxRateIds: String
  """The line total, as calculated and stored by the server."""
  totalPrice: Float!
  """Price per unit before the line discount."""
  unitPrice: Float!
  """The unit of measure of this line."""
  uom: UnitOfMeasure
  """The ID of the unit of measure the quantity is expressed in."""
  uomId: String
  """Name of the unit of measure."""
  uomName: String
  """When the record was last changed."""
  updatedAt: DateTime!
  """The ID of the user who last changed the record."""
  updatedBy: String!
  """The product variant on this line."""
  variant: ProductVariant
  """The ID of the product variant on this line."""
  variantId: String
  """The variant name, as stored on the line."""
  variantName: String
  """The warehouse this line is fulfilled from."""
  warehouse: Warehouse
  """The ID of the warehouse this line is fulfilled from."""
  warehouseId: String
}

"""Headline figures for the quotes matching a filter."""
type QuoteListSummary {
  """
  Quotes with a settled outcome: won, rejected or expired. The denominator of the win rate.
  """
  decidedCount: Int!
  """Live quotes whose valid-until date falls within the next 7 days."""
  expiringSoonCount: Int!
  """
  Quotes still with the seller or awaiting an answer (draft, sent or pending).
  """
  pendingCount: Int!
  """Every quote the filter matches."""
  totalCount: Int!
  """
  Total value of live quotes in the organization's base currency. Cancelled, rejected and expired quotes are excluded.
  """
  totalValue: Float!
  """
  Won quotes as a whole percent of decided quotes. 0 when nothing is decided.
  """
  winRate: Int!
  """
  Quotes won, whichever step recorded it (accepted, converted or approved).
  """
  wonCount: Int!
}

"""A column the quote list can be sorted by."""
enum QuoteSortField {
  """When the quote was created."""
  CREATED_AT
  """The last activity on the quote."""
  LAST_ACTIVITY_AT
  """The quote date."""
  QUOTE_DATE
  """The total amount."""
  TOTAL_AMOUNT
  """When the quote was last changed."""
  UPDATED_AT
  """The date the quote expires."""
  VALID_UNTIL
}

"""Number of quotes in each status, for the quotes matching a filter."""
type QuoteStatusCounts {
  """Quotes accepted by the customer."""
  ACCEPTED: Int!
  """Quotes approved."""
  APPROVED: Int!
  """Quotes cancelled."""
  CANCELLED: Int!
  """Quotes converted to an order or invoice."""
  CONVERTED: Int!
  """Quotes in draft."""
  DRAFT: Int!
  """Quotes past their valid-until date."""
  EXPIRED: Int!
  """Quotes awaiting approval or an answer."""
  PENDING: Int!
  """Quotes rejected."""
  REJECTED: Int!
  """Quotes sent to the customer."""
  SENT: Int!
  """Quotes the customer has viewed."""
  VIEWED: Int!
}

"""Sales figures from quote to payment."""
type QuoteToCashAnalytics {
  """The average days between stages."""
  avgCycleDays: CycleTimes!
  """The share of quotes that became orders, in percent."""
  conversionRatePct: Float!
  """The funnel from quote to payment."""
  funnel: [FunnelStage!]!
  """The value of open quotes."""
  pipelineValue: Float!
  """Values over the period."""
  trend: [TrendPoint!]!
  """The share of decided quotes that were won, in percent."""
  winRatePct: Float!
}

"""
A page of quotes with paging metadata, summary figures and per-status counts.
"""
type QuotesPaginatedResponse {
  """Whether there are more quotes to load"""
  hasMore: Boolean!
  """Cursor for next page (null if no more pages)"""
  nextCursor: String
  """List of quotes for current page"""
  quotes: [Quote!]!
  """Quote counts per status for Kanban headers"""
  statusCounts: QuoteStatusCounts!
  """Total count of quotes matching the filter"""
  totalCount: Int!
}

"""One reason and how often it applies."""
type ReasonSlice {
  """How many times."""
  count: Int!
  """The reason."""
  reason: String!
  """Their value."""
  value: Float!
}

"""
A notice to the previous rep that a customer was moved away. It carries only the name, code, date and who did it.
"""
type ReassignmentNotice {
  """The customer code."""
  customerCode: String
  "The ID of the customer."
  customerId: ID!
  """The name of the customer."""
  customerName: String!
  """When the customer was moved."""
  reassignedAt: DateTime!
  """The name of the user who moved it."""
  reassignedByName: String
}

"""What customers owe the organization."""
type ReceivablesAnalytics {
  """Open invoices by age."""
  aging: [AgingBucket!]!
  """
  The average days between an invoice's date and the payment allocated to it, for payments received in the range. Counts only invoices that were paid, so it is not days sales outstanding. 0 when nothing was collected.
  """
  avgDaysToCollect: Float!
  """Cash collected over the period."""
  collectionTrend: [CollectionTrendPoint!]!
  """
  Days sales outstanding: open invoices at the end of the range ÷ invoices issued in the range × days in the range, to one decimal. Null when no invoice was issued in the range. Base currency; credit notes are not netted, and the open balance is each invoice's current outstanding amount.
  """
  dsoDays: Float
  """What the organization owes its vendors."""
  payables: PayablesAnalytics!
  """The customers who owe the most."""
  topDebtors: [DebtorSlice!]!
}

"""Input to receive goods against a purchase order."""
input ReceivePurchaseOrderInput {
  """The ID of the purchase order."""
  id: ID!
  """The lines being received."""
  items: [ReceivePurchaseOrderItemInput!]!
  """Notes on the receipt."""
  notes: String
}

"""A line being received against a purchase order."""
input ReceivePurchaseOrderItemInput {
  """Batch or lot number of the goods received."""
  batchNumber: String
  """The ID of the warehouse bin the goods are put away to."""
  binId: String
  """Expiry date of the batch."""
  expiryDate: DateTime
  """The ID of the purchase order line."""
  itemId: ID!
  """Quantity received now, in the line's unit of measure."""
  receivedQuantity: Float!
  "The ID of the warehouse."
  warehouseId: String
}

"""Recent stock movements of one type, totalled."""
type RecentMovementSummary {
  """How many movements of this type."""
  count: Int!
  """The total quantity moved."""
  quantity: Float!
  """The movement type."""
  type: MovementType!
  """The total value moved."""
  value: Float!
}

"""Records a batch of buyer interaction events."""
input RecordBuyerActivityInput {
  """The events."""
  events: [BuyerActivityEventInput!]!
}

"""The result of recording events."""
type RecordBuyerActivityResult {
  """
  How many events were stored. 0 while recording is off or in shadow mode.
  """
  accepted: Int!
  """
  How many events were refused: unknown or server-only names, or clocks too old or too far ahead.
  """
  rejected: Int!
}

"""Records a contact's consent."""
input RecordContactConsentInput {
  """The channel the consent is for."""
  channel: ConsentChannel!
  """The ID of the contact."""
  contactId: ID!
  """What the consent is for."""
  purpose: ConsentPurpose!
  """Who is attesting. Only REP_ATTESTED and ADMIN are accepted here."""
  source: ConsentSource!
  """Whether the contact opted in or out."""
  status: ConsentStatus!
}

"""A status recorded by hand, for a custom courier."""
input RecordShipmentStatusInput {
  """A note about the update."""
  note: String
  """When it happened."""
  occurredAt: DateTime
  """The new status."""
  status: ShipmentStatus!
  """The tracking number to add or correct."""
  trackingNumber: String
}

"""Gets a new access token from a refresh token."""
input RefreshTokenInput {
  """The refresh token."""
  refreshToken: String!
}

"""How a customer is compensated for a return."""
enum RefundMethod {
  """Refund by bank transfer."""
  BANK_TRANSFER
  """Refund in cash."""
  CASH
  """Refund to the credit card."""
  CREDIT_CARD
  """Refund as a credit note."""
  CREDIT_NOTE
  """Refund as a debit note."""
  DEBIT_NOTE
  """Repair the item instead of refunding."""
  REPAIR
  """Send a replacement instead of refunding."""
  REPLACEMENT
  """Refund as store credit."""
  STORE_CREDIT
}

"""A region such as a country, state or city."""
type Region {
  """The name of the city."""
  cityName: String
  """The region code."""
  code: String!
  """The country code."""
  countryCode: String
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The name of the region."""
  name: String!
  """The ID of the region this one is inside."""
  parentRegionId: String
  """The pattern postal codes follow."""
  postalCodePattern: String
  """The state code."""
  stateCode: String
  """The time zone of the region."""
  timezone: String
  """The kind of region."""
  type: RegionType!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""Sales in one region."""
type RegionData {
  """How many orders."""
  orders: Int!
  """The region."""
  region: String!
  """The sales value."""
  sales: Float!
}

"""Type of geographical region"""
enum RegionType {
  """A city."""
  CITY
  """A continent."""
  CONTINENT
  """A country."""
  COUNTRY
  """A region you define."""
  CUSTOM
  """A state or province."""
  STATE
}

"""Registers a new customer account."""
input RegisterCustomerInput {
  """
  The registrant's first address, collected as the second step of signup and created in the SAME transaction as the Partner. It rides on registration rather than being added afterwards because a tenant that screens new customers gives them no session — so an address collected after sign-in is an address a PENDING account can never enter. Optional: a tenant that does not screen its customers may also let them skip it and add one later.
  """
  address: CustomerAddressInput
  """
  Whether the registrant is a business or an individual → the `Partner.type` COLUMN (mirrored onto `Partner.metadata.businessType`), the SAME field the seller console's customer form edits and `myProfile.businessType` reads back. Omitted defaults to BUSINESS.
  """
  businessType: BuyerBusinessType
  """
  The 6-digit code the registrant already verified on the OTP screen, which now comes BEFORE this form (mirroring the buyer app's email → OTP → details order, owner decision 2026-08-11). Re-checked server-side here because this mutation is what actually creates the account: without it, registration is callable directly and 'verified email' would be a client-side claim (Foundation Gate 3). The code is NOT consumed here — the sign-in that follows spends it.
  """
  code: String!
  """The name of the company."""
  companyName: String!
  """
  The person's full name. Still REQUIRED — it is what every existing reader renders, and older portal builds send only this. When `firstName`/`lastName` are also sent they win, because a split of "Ana Maria Da Silva" can only guess where the surname starts and the form already knows.
  """
  contactName: String!
  """
  The person's department (e.g. 'Procurement'). Stored on their `Contact` rows, like `title`.
  """
  department: String
  "Email address."
  email: String!
  """
  Given name. Optional for older builds sending only `contactName`; takes precedence over splitting it when present.
  """
  firstName: String
  """Family name. See `firstName`."""
  lastName: String
  """
  Mobile number in E.164 form (e.g. +27821234567) → User.phone plus a PHONE `Contact` channel row.
  """
  phone: String
  """
  Dev/localhost fallback for multi-tenant resolution — the request host (X-Original-Host → Host) always wins, exactly like checkCustomerExists.
  """
  subdomain: String
  """
  The person's job title (e.g. 'Purchasing Manager'). Stored on their `Contact` rows — there is no title column on `User`. Same field as MobileRegisterBuyerInput.title.
  """
  title: String
  """
  WhatsApp number in E.164 form. Persisted as its own WHATSAPP `Contact` channel row — there is no WhatsApp column on `User`. The portal form offers a "Same as mobile number" tick, exactly like the seller console and the buyer app.
  """
  whatsapp: String
}

"""Registers a device for push messages."""
input RegisterPushTokenInput {
  """The version of the app."""
  appVersion: String
  """The ID of the device."""
  deviceId: ID!
  """The platform of the device."""
  platform: MobilePushPlatform!
  """The push token."""
  token: String!
}

"""Removes an item from the cart."""
input RemoveCartItemInput {
  """The ID of the cart item."""
  cartItemId: ID!
  """CAS guard: the cart revision this mutation was read against."""
  expectedRevision: Int
  """Client-minted id for replay-safety (same id+payload = no-op success)."""
  operationId: String
}

"""Takes a permission away from a role."""
input RemovePermissionInput {
  """The ID of the permission."""
  permissionId: ID!
  "The ID of the role."
  roleId: ID!
}

"""Takes a user out of a role."""
input RemoveUserFromRoleInput {
  "The ID of the role."
  roleId: ID!
  "The ID of the user."
  userId: ID!
}

"""Removes a permission granted directly to a user."""
input RemoveUserPermissionInput {
  """The ID of the permission."""
  permissionId: ID!
  "The ID of the user."
  userId: ID!
}

"""Renames an attribute on every product carrying it."""
input RenameProductAttributeInput {
  """The attribute, in any spelling."""
  attributeKey: String!
  """
  When the new name is another existing attribute: true merges into it (a variant carrying both keeps the existing attribute's value); otherwise the rename is refused with code PRODUCT_ATTRIBUTE_EXISTS.
  """
  merge: Boolean
  """The new name."""
  name: String!
}

"""Renames one value on every product carrying it."""
input RenameProductAttributeValueInput {
  """The attribute, in any spelling."""
  attributeKey: String!
  """
  When the new value already exists: true merges into it; otherwise the rename is refused with code PRODUCT_ATTRIBUTE_VALUE_EXISTS.
  """
  merge: Boolean
  """The new value."""
  newValue: String!
  """The value as variants carry it."""
  value: String!
}

"""A rep's commission setup."""
type RepCommissionProfile {
  """The rep's default commission rate, in percent."""
  defaultRate: Float!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The email address of the rep."""
  repEmail: String
  """The name of the rep."""
  repName: String
  "The ID of the user."
  userId: String!
}

"""A rep's commission totals."""
type RepCommissionSummary {
  """The commission earned in each period."""
  byPeriod: [PeriodAmount!]!
  """The commission earned."""
  earned: Float!
  """The commission paid."""
  paid: Float!
  """The commission still pending."""
  pending: Float!
}

"""The discount one rep gave."""
type RepLeakage {
  """The discount given."""
  discount: Float!
  """The discount as a percent of revenue plus discount."""
  pct: Float!
  """The ID of the rep."""
  repId: ID!
  """The name of the rep."""
  repName: String!
}

"""One rep's results."""
type RepPerformance {
  """The commission the rep earned."""
  commissionEarned: Float!
  """The commission still pending."""
  commissionPending: Float!
  """How many orders the rep won."""
  orders: Int!
  """How many quotes the rep raised."""
  quotes: Int!
  """The ID of the rep."""
  repId: String!
  """The name of the rep."""
  repName: String!
  """The revenue from the rep's orders."""
  revenue: Float!
  """The share of the rep's decided quotes that were won, in percent."""
  winRatePct: Float!
}

"""Asks for a one-time code to sign in."""
input RequestCustomerOtpInput {
  "Email address."
  email: String!
  """The subdomain of the organization the customer signs in to."""
  subdomain: String
}

"""
Asks for a one-time code to change the buyer's own email address. The organization comes from the sign in.
"""
input RequestEmailChangeOtpInput {
  """The NEW address to send the verification code to."""
  email: String!
}

"""Asks for a one-time code by email to sign in."""
input RequestEmailOtpInput {
  "Email address."
  email: String!
  """
  ARC org subdomain this white-label build is pinned to (Constants.expoConfig.extra.orgSubdomain). Determines which tenant the OTP/login is scoped to. Optional only for backward-compat / dev fallback (MOBILE_BUYER_ORG_ID).
  """
  subdomain: String
}

"""Asks for a one-time code to sign in."""
input RequestOtpInput {
  "Email address."
  email: String!
  """The subdomain of the organization the code is for."""
  subdomain: String
}

"""
Step 1 of signing up: asks for a one-time code to verify an email address.
"""
input RequestRegistrationOtpInput {
  "Email address."
  email: String!
}

"""
The result of step 1 of signing up. The code is only ever sent by email.
"""
type RequestRegistrationOtpResponse {
  """A message about the outcome."""
  message: String
  """Opaque id that must be passed back to verifyRegistrationOtp"""
  requestId: String!
  """True when the code was sent."""
  success: Boolean!
}

"""Asks for a one-time code by WhatsApp to sign in."""
input RequestWhatsAppOtpInput {
  """
  Email used as primary identity; WhatsApp number is looked up from profile or supplied later.
  """
  email: String!
}

"""The result of resetting an organization's data."""
type ResetDataResult {
  """How many records of each kind were deleted."""
  details: JSON!
  """A message about the outcome."""
  message: String!
  """True when the reset finished."""
  success: Boolean!
  """How many records were deleted."""
  totalDeleted: Int!
}

"""How many records a data reset would delete."""
type ResetDataSummary {
  """How many brands."""
  brands: Int!
  """How many categories."""
  categories: Int!
  """How many credit notes."""
  creditNotes: Int!
  """How many discount schemes."""
  discountSchemes: Int!
  """How many invoices."""
  invoices: Int!
  """How many customers and vendors."""
  partners: Int!
  """How many payments."""
  payments: Int!
  """How many products."""
  products: Int!
  """How many purchase orders."""
  purchaseOrders: Int!
  """How many quotes."""
  quotes: Int!
  """How many sales orders."""
  salesOrders: Int!
  """The total number of records."""
  totalRecords: Int!
  """How many variants."""
  variants: Int!
}

"""Sets a new password from a reset link."""
input ResetPasswordInput {
  """The new password."""
  password: String!
  """The token from the reset link."""
  token: String!
}

"""
How staff resolve a booking that is stuck, after checking with the courier. Neither action calls the carrier.
"""
input ResolveOrphanedShipmentInput {
  """
  CONFIRM_BOOKED when the courier holds the booking, MARK_CANCELLED when staff cancelled it with the courier.
  """
  action: ShipmentOrphanResolution!
  """What staff found at the courier. Kept on the shipment timeline."""
  note: String
  """
  The courier's own shipment ID, so tracking resumes. Only for CONFIRM_BOOKED.
  """
  providerShipmentId: String
  """
  The courier's tracking number, when it has one. Only for CONFIRM_BOOKED.
  """
  trackingNumber: String
}

"""A brand matched or created for a product."""
type ResolvedBrand {
  "The unique ID of this record."
  id: ID!
  """The name of the brand."""
  name: String!
}

"""
The result of an RMA step that does not return a record, such as an inspection.
"""
type ReturnActionResult {
  "The ID of the credit note."
  creditNoteId: String
  """A message about the outcome."""
  message: String!
  """True when the step was done."""
  success: Boolean!
}

"""A credit note raised from a return."""
type ReturnCreditNote {
  """The amount before tax."""
  amount: Float!
  """The credit note number."""
  creditNoteNumber: String!
  "The unique ID of this record."
  id: ID!
  """The date the note was issued."""
  issueDate: DateTime!
  """The status of the note."""
  status: String!
  """The tax on the note."""
  taxAmount: Float!
  """The total including tax."""
  totalAmount: Float!
  """The credit note type."""
  type: String!
}

"""A debit note raised from a return."""
type ReturnDebitNote {
  """The amount before tax."""
  amount: Float!
  """The debit note number."""
  debitNoteNumber: String!
  "The unique ID of this record."
  id: ID!
  """The date the note was issued."""
  issueDate: DateTime!
  """The status of the note."""
  status: String!
  """The tax on the note."""
  taxAmount: Float!
  """The total including tax."""
  totalAmount: Float!
  """The debit note type."""
  type: String!
}

"""Filters and sorting for the returns list."""
input ReturnFilterInput {
  """Only returns dated on or before this date."""
  endDate: DateTime
  "The ID of the partner."
  partnerId: String
  "Text to search for."
  search: String
  """The column to sort by. Defaults to newest return date first."""
  sortBy: ReturnSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only returns dated on or after this date."""
  startDate: DateTime
  """Only returns in this status."""
  status: ReturnStatus
  """Only returns of this kind."""
  type: ReturnType
  "The ID of the warehouse."
  warehouseId: String
}

"""One line of a return."""
input ReturnItemInput {
  """The condition the item is in."""
  condition: ItemCondition!
  """Notes about the line."""
  notes: String
  """
  The ID of the order line the item comes back against. Needed when the order lists the same variant on two lines, otherwise the first line with room is used.
  """
  originalOrderItemId: String
  "The ID of the product."
  productId: String!
  """The quantity returned. Must be greater than zero."""
  quantity: Float!
  """The price of one unit."""
  unitPrice: Float!
  "The ID of the product variant."
  variantId: String!
}

"""A page of returns and the total number that match."""
type ReturnListResponse {
  """The returns on this page."""
  returns: [ProductReturn!]!
  """How many returns match the filter in all."""
  total: Int!
}

"""
Totals for the returns list, counted over the whole filtered set rather than one page.
"""
type ReturnListSummary {
  """How many are waiting for approval."""
  awaitingApprovalCount: Int!
  """How many are processed or completed."""
  doneCount: Int!
  """
  How many are open and not yet processed, including those awaiting approval.
  """
  openCount: Int!
  """How many returns match the filter, rejected and cancelled included."""
  totalCount: Int!
  """
  The total value of the returns, in the organization's base currency. Rejected and cancelled returns are left out.
  """
  totalValue: Float!
}

"""Returns of one product."""
type ReturnProductSlice {
  """How many returns."""
  count: Int!
  """The name of the product."""
  productName: String!
  """Their value."""
  value: Float!
}

"""Why goods are returned."""
enum ReturnReason {
  """Arrived damaged."""
  DAMAGED
  """Does not work."""
  DEFECTIVE
  """Past its expiry date."""
  EXPIRED
  """The wrong item was sent."""
  INCORRECT
  """The customer no longer wants it."""
  NOT_REQUIRED
  """Any other reason."""
  OTHER
}

"""A return created through the RMA flow."""
type ReturnResponse {
  "The unique ID of this record."
  id: String!
  """The return number."""
  returnNumber: String!
  """The return merchandise authorization number, if one was issued."""
  rmaNumber: String
  """The status of the return."""
  status: String!
}

"""A column the returns list can be sorted by."""
enum ReturnSortField {
  """When the return was created."""
  CREATED_AT
  """The return date."""
  RETURN_DATE
  """The total amount."""
  TOTAL_AMOUNT
}

"""
Where a return stands. Console returns go PENDING to PROCESSED. RMA returns go from DRAFT or PENDING_APPROVAL through APPROVED, IN_TRANSIT, RECEIVED, INSPECTING and PROCESSING to COMPLETED, or end as REJECTED or CANCELLED.
"""
enum ReturnStatus {
  """Approved."""
  APPROVED
  """Cancelled."""
  CANCELLED
  """Finished."""
  COMPLETED
  """Being prepared."""
  DRAFT
  """Being inspected."""
  INSPECTING
  """On its way back."""
  IN_TRANSIT
  """Partly processed."""
  PARTIAL
  """Waiting."""
  PENDING
  """Waiting for approval."""
  PENDING_APPROVAL
  """Processed."""
  PROCESSED
  """Being processed."""
  PROCESSING
  """Received."""
  RECEIVED
  """Turned down."""
  REJECTED
}

"""
The kind of return. Console returns are SALES_RETURN or PURCHASE_RETURN. The other kinds come from the RMA flow.
"""
enum ReturnType {
  """Defective goods."""
  DEFECTIVE_RETURN
  """An exchange."""
  EXCHANGE_RETURN
  """Stock returned between internal locations."""
  INTERNAL_RETURN
  """Goods sent back to a supplier."""
  PURCHASE_RETURN
  """Goods sent back by a customer."""
  SALES_RETURN
  """A service return."""
  SERVICE_RETURN
  """A warranty claim."""
  WARRANTY_RETURN
}

"""How many goods came back."""
type ReturnsAnalytics {
  """Returns by product."""
  byProduct: [ReturnProductSlice!]!
  """Returns by reason."""
  byReason: [ReasonSlice!]!
  """The value of credit notes issued."""
  creditNoteValue: Float!
  """The share of sales that were returned, in percent."""
  returnRatePct: Float!
  """The value of returns."""
  totalReturnValue: Float!
}

"""Revenue, expenses and profit for one period."""
type RevenueData {
  """The expenses."""
  expenses: Float!
  """The period."""
  period: String!
  """The profit."""
  profit: Float!
  """The revenue."""
  revenue: Float!
}

"""
Reverses specific allocations of a payment. The originals are kept and a negative counter-entry is added.
"""
input ReversePaymentAllocationsInput {
  """
  The IDs of the allocations to reverse. Each reversal is recorded as a counter-entry; the original allocation is never deleted.
  """
  allocationIds: [ID!]!
  """
  The version of the payment you last read. The change is refused if someone else changed it since.
  """
  expectedVersion: Int
  """The ID of the payment whose allocations to reverse."""
  paymentId: ID!
  """Why the allocations are being reversed."""
  reason: String
}

"""A role: a named set of permissions that can be given to users."""
type Role {
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the role is for."""
  description: String
  """The name to show for the role."""
  displayName: String!
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """True when the role is built in."""
  isSystem: Boolean!
  """Extra information about the role, as JSON text."""
  metadata: String
  """The name of the role."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """How many permissions the role has."""
  permissionCount: Int
  """The permissions of the role."""
  permissions: [Permission!]
  """The rank of the role."""
  priority: Int!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """How many users are in the role."""
  userCount: Int
  """The users in the role."""
  users: [User!]
}

"""The result of rolling back a batch of changes."""
type RollbackBatchResult {
  """The ID of the batch."""
  batchId: String!
  """How many records were deleted."""
  deleted: Int!
  """What happened to each record that needed a note."""
  details: [String!]!
  """How many records failed."""
  failed: Int!
  """How many records were restored."""
  restored: Int!
  """How many records were skipped."""
  skipped: Int!
  """The status of the batch after the rollback."""
  status: String!
}

"""A request to route to the right storefront action."""
input RouteStorefrontRequestInput {
  """
  The sections already on the page, top to bottom, as 'handle@version'. No values or copy.
  """
  currentPage: [String!]
  """
  How many images the seller attached to the message (0-3). The images themselves are never sent here.
  """
  imageCount: Int
  """'home' or 'page'."""
  pageType: String
  """Where on the page new content goes, in words (e.g. 'below Hero')."""
  placement: String
  """The seller's own chat message, exactly as typed."""
  request: String!
}

"""
A rule that builds SKUs from placeholders such as brand, category and a running number.
"""
type SKUPattern {
  """The brand the pattern applies to."""
  brand: Brand
  "The ID of the brand."
  brandId: ID
  """The category the pattern applies to."""
  category: Category
  "The ID of the category."
  categoryId: ID
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the pattern is for."""
  description: String
  "The ID of the user who created the record."
  enteredBy: String!
  """An example of a generated SKU."""
  example: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The name of the pattern."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The pattern, using placeholders such as {BRAND}-{CATEGORY}-{SEQ}."""
  pattern: String!
  """Which pattern wins when several match. Defaults to 1."""
  priority: Int!
  """How many digits the running number has. Defaults to 4."""
  sequenceLength: Int!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""Sales figures for the period."""
type SalesAnalytics {
  """The average order value."""
  averageOrderValue: Float!
  """The growth in orders against the previous period, in percent."""
  ordersGrowth: Float!
  """Sales over time."""
  salesByPeriod: [PeriodData!]!
  """Sales split by region."""
  salesByRegion: [RegionData!]!
  """The growth in sales against the previous period, in percent."""
  salesGrowth: Float!
  """The customers who bought the most."""
  topCustomers: [TopCustomer!]!
  """The products that sold the most."""
  topProducts: [TopProduct!]!
  """How many orders there were."""
  totalOrders: Int!
  """The total sales value."""
  totalSales: Float!
}

"""
FULL: reps see every courier, service and price. CUSTOMER: reps see what customers see.
"""
enum SalesAppDeliveryView {
  """Reps see what customers see."""
  CUSTOMER
  """Reps see every courier, service and price."""
  FULL
}

"""Sales in one category."""
type SalesByCategory {
  """The name of the category."""
  category: String!
  """Its share of all revenue, in percent."""
  percentage: Float!
  """The revenue."""
  revenue: Float!
}

"""
A confirmed demand from a customer to ship goods, usually converted from a quote. Moves through confirmation, shipment, invoicing and payment.
"""
type SalesOrder {
  """The billing address on the order."""
  billingAddress: SalesOrderAddress
  """
  Branch attribution: the branch Address id this order was placed for. Null on partner-level orders.
  """
  branchAddressId: String
  """
  True when the branch address is soft-deleted, un-flagged, or inactive (EDGE) — the label still renders.
  """
  branchInactive: Boolean
  """
  Branch display name (the branch Address label), resolved org-scoped. Null when the order has no branch.
  """
  branchLabel: String
  """
  The courier plan: customer's original courier and price, the active staff change with courier charge, customer share, seller share and reason, and the history. Null unless the caller may ship orders (sales:sales_order:ship).
  """
  courierPlan: CourierPlan
  """When the record was created."""
  createdAt: DateTime!
  """The ID of the user who created the order."""
  createdBy: String!
  """The name of the user who created the order."""
  creatorName: String!
  """Currency code of the document's amounts."""
  currency: String
  """The customer's email address, as stored on the order."""
  customerEmail: String
  """The ID of the customer who placed the order."""
  customerId: String!
  """The customer's mobile number, as stored on the order."""
  customerMobile: String
  """The customer's name, as stored on the order."""
  customerName: String!
  """Buyer-supplied PO number (portal checkout)."""
  customerPoNumber: String
  """When the record was deleted. Null while it is active."""
  deletedAt: DateTime
  """When the order was delivered. Null until delivered."""
  deliveredDate: DateTime
  """Delivery instructions for the shipment."""
  deliveryInstructions: String
  """
  The live delivery option recorded on the order (the buyer's checkout choice or the rep's pick): partner, carrier, service, agreed amount and currency. Null when none.
  """
  deliverySelection: ShipmentCustomerChoice
  """Total discount amount on the order."""
  discountAmount: Float!
  """
  Exchange rate between the document currency and the organization's base currency, when they differ.
  """
  exchangeRate: Float
  """
  Set when the order was too heavy to price delivery live (box packing freight threshold): placed with no delivery charge for staff to quote. Null otherwise.
  """
  freightQuote: SalesOrderFreightQuote
  """Unique identifier of the record."""
  id: ID!
  """Notes for your team only; never shown to the customer."""
  internalNotes: String
  """Number of lines on the order."""
  itemCount: Int!
  """The line items on the order."""
  items: [SalesOrderItem!]!
  """
  Per order line: units already on returns made against this order, and units a new return may still take (ordered less returned). Creating a return refuses more.
  """
  lineReturns: [OrderLineReturns!]!
  """Notes on the document, visible to the customer."""
  notes: String
  """
  The online (payment gateway) payment that settled this order. Null for EFT / on-account / COD orders and unpaid ones; only populated on the single-order read.
  """
  onlinePayment: SalesOrderOnlinePayment
  """The date the order was placed."""
  orderDate: DateTime!
  """The human-readable sales order number, unique within the organization."""
  orderNumber: String!
  """The ID of the organization (tenant) that owns the record."""
  organizationId: String!
  """How much of the order has been paid. See PaymentStatus."""
  paymentStatus: PaymentStatus!
  """
  Money received against the order, the balance still to take, the part a second person verified and portal transfers awaiting the seller's acceptance. Null when the order cannot be read.
  """
  paymentSummary: SalesOrderPaymentSummary
  """The payment terms agreed for the order."""
  paymentTerms: String!
  """
  The delivery date promised to the customer. Null when none was promised.
  """
  promisedDate: DateTime
  """
  Purchase orders raised to supply this order (reverse-resolved from PurchaseOrder.sourceSalesOrderId). Only populated on the single-order read.
  """
  purchaseOrders: [LinkedPurchaseOrderRef!]
  """Your own reference for the order."""
  reference: String
  """When the order was shipped. Null until it ships."""
  shippedDate: DateTime
  """The shipping address on the order."""
  shippingAddress: SalesOrderAddress
  """Shipping charge on the order."""
  shippingAmount: Float!
  """The shipping method chosen for the order."""
  shippingMethod: String
  """The reason given when the order was short-closed."""
  shortCloseReason: String
  """When the order was short-closed. Null if it was not."""
  shortClosedAt: DateTime
  """The ID of the user who short-closed the order."""
  shortClosedBy: String
  """
  Id of the quote this order was converted from (reverse-resolved from Quote.convertedToSalesOrderId). Null for a directly created order; only populated on the single-order read.
  """
  sourceQuoteId: String
  """
  Number of the quote this order was converted from. Null for a directly created order; only populated on the single-order read.
  """
  sourceQuoteNumber: String
  """
  Where the order is in its lifecycle. See SalesOrderStatus for the values and the allowed transitions.
  """
  status: SalesOrderStatus!
  """Subtotal of the order lines, as calculated by the server."""
  subtotal: Float!
  """Total tax on the order."""
  taxAmount: Float!
  """
  Whether line prices include tax (INCLUSIVE) or tax is added on top (EXCLUSIVE).
  """
  taxCalculationMethod: String
  """
  The order total in the order currency, as calculated and stored by the server.
  """
  totalAmount: Float!
  """The carrier tracking number, once shipped."""
  trackingNumber: String
  """When the record was last changed."""
  updatedAt: DateTime!
  """
  Optimistic-concurrency counter — pass back as expectedVersion on the next mutation.
  """
  version: Int!
  """The warehouse the order is fulfilled from."""
  warehouse: Warehouse
  """The ID of the warehouse the order is fulfilled from."""
  warehouseId: String
}

"""A postal address on a sales order."""
type SalesOrderAddress {
  """City."""
  city: String
  """Country."""
  country: String
  """Postal code."""
  postalCode: String
  """State or region."""
  state: String
  """First line of the street address."""
  street1: String
  """Second line of the street address."""
  street2: String
}

"""A sales order row that failed to import."""
type SalesOrderBulkImportError {
  """What was wrong with the row."""
  errors: [String!]!
  """The order number on that row, if given."""
  orderNumber: String
  """Row number in the import file, starting at 1."""
  row: Int!
}

"""Result of a bulk sales order import."""
type SalesOrderBulkImportResult {
  """The failed rows and why."""
  errors: [SalesOrderBulkImportError!]!
  """Number of orders that failed."""
  failed: Int!
  """Number of orders imported."""
  success: Int!
}

"""
What the approval rules would decide if this sales order were confirmed now, checked without confirming it.
"""
type SalesOrderConfirmPreview {
  """
  The refusal the confirm would end in: CONTROL_BLOCKED, CONTROL_APPROVAL_REQUIRED or CONTROL_NO_ELIGIBLE_APPROVER. Null for PASS and NOT_CHECKED.
  """
  code: String
  """The deciding rule's ID."""
  controlId: String
  """The deciding rule's own message, when it has one."""
  message: String
  """
  PASS, NEEDS_APPROVAL, BLOCK, or NOT_CHECKED when another change was using the order's records (the rules are checked again on confirm).
  """
  outcome: String!
}

"""
One email sent or received about a sales order, with its delivery and engagement tracking.
"""
type SalesOrderEmailActivity {
  """Number of attachments on the email."""
  attachmentCount: Int!
  """The email body as HTML."""
  bodyHtml: String
  """A short plain-text preview of the body."""
  bodyPreview: String
  """
  The provider's reason for the bounce. Null when the email did not bounce.
  """
  bounceReason: String
  """
  Kind of bounce reported by the provider (for example hard or soft). Null when the email did not bounce.
  """
  bounceType: String
  """When the email bounced. Null when it did not."""
  bouncedAt: DateTime
  """Addresses copied on the email."""
  ccEmails: [String!]!
  """Total link clicks recorded across all recipients."""
  clickCount: Int!
  "When the record was created."
  createdAt: DateTime!
  """When the provider confirmed delivery. Null until delivered."""
  deliveredAt: DateTime
  """
  Whether the email was sent by you (OUTBOUND) or received from the customer (INBOUND).
  """
  direction: String!
  """When the email was first opened. Null if never opened."""
  firstOpenAt: DateTime
  """Sender address."""
  fromEmail: String!
  """Sender display name."""
  fromName: String
  """Whether the email carries at least one attachment."""
  hasAttachment: Boolean!
  "The unique ID of this record."
  id: ID!
  """
  The ID of the email this one replies to, used to thread the conversation.
  """
  inReplyToId: String
  """Whether this email is a reply to an earlier one."""
  isReply: Boolean!
  """When the email was last opened. Null if never opened."""
  lastOpenAt: DateTime
  """Total opens recorded."""
  openCount: Int!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """
  When the reply was processed into the document's activity. Null until processed.
  """
  processedAt: DateTime
  """The ID of the user who processed the reply. Null when unprocessed."""
  processedBy: String
  """The email provider that sent or received the message."""
  provider: String!
  """The provider's own ID for the message."""
  providerMessageId: String
  "The ID of the sales order."
  salesOrderId: String!
  """When the email was sent or received."""
  sentAt: DateTime!
  """
  Delivery status of the email (for example SENT, DELIVERED, OPENED, BOUNCED).
  """
  status: String!
  """
  For a reply, the new text only, with the quoted earlier thread removed.
  """
  strippedTextReply: String
  """Subject line."""
  subject: String!
  """The email body as plain text."""
  textBody: String
  """Recipient address."""
  toEmail: String!
  """Recipient display name."""
  toName: String
  """Number of distinct recipients who opened the email."""
  uniqueOpens: Int!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""Filters for listing sales orders."""
input SalesOrderFiltersInput {
  """
  When true, only confirmed orders that still have items to ship: invoiced orders count until everything has shipped, and short-closed quantities are left out. The same orders as the dashboard's Orders Awaiting Fulfilment.
  """
  awaitingFulfilment: Boolean
  """Only orders created by this user."""
  createdBy: String
  """Only orders for this customer."""
  customerId: ID
  """Only orders dated on or before this date."""
  endDate: DateTime
  """Only orders with this payment status."""
  paymentStatus: PaymentStatus
  """Text to search for in orders."""
  search: String
  """Field to sort by. Omitted means most recently updated first."""
  sortBy: SalesOrderSortField
  """Sort direction."""
  sortOrder: SortOrder
  """Only orders dated on or after this date."""
  startDate: DateTime
  """Only orders in these statuses."""
  status: [SalesOrderStatus!]
  """
  Only orders changed strictly after this instant. Used for incremental sync; it can only narrow what the caller may see.
  """
  updatedAfter: DateTime
}

"""
A freight quote for a sales order: the carrier options and their charges.
"""
type SalesOrderFreightQuote {
  """How many boxes it packed into."""
  boxCount: Int!
  """
  True while the delivery charge is still unset (shipping 0, not invoiced yet): createInvoice refuses with DELIVERY_FREIGHT_CHARGE_UNSET unless confirmZeroDeliveryCharge is true.
  """
  chargePending: Boolean!
  """When the order was placed as a freight quote."""
  decidedAt: DateTime
  """The packed weight that crossed the threshold (kg, boxes included)."""
  packedWeightKg: Float!
}

"""
A line on a sales order: a product or variant, quantity, price, discount and tax, with its shipped and invoiced progress.
"""
type SalesOrderItem {
  """
  Buyer consent: if this item becomes unavailable, may fulfillment ship a manually-picked substitute instead? Consent + visibility only.
  """
  acceptAlternativeIfUnavailable: Boolean!
  """Quantity allocated to this line."""
  allocatedQuantity: Float!
  """
  Not populated: currently always 0. Use the inventory queries for stock on hand.
  """
  availableQuantity: Float!
  """Quantity cancelled on this line."""
  canceledQuantity: Float
  """How many base units one unit of the line's unit of measure equals."""
  conversionFactor: Float!
  """When the line was created."""
  createdAt: DateTime!
  """Total discount amount on the line."""
  discountAmount: Float!
  """
  Attribution of discountAmount: [{ kind: "TIER" | "SCHEME" | "MANUAL", label: string, percent: number | null, amount: "<exact decimal string>" }]. Null when the line carries no discount or predates the column.
  """
  discountBreakdown: JSON
  """The line discount as a percentage."""
  discountPercent: Float!
  """Unique identifier of the record."""
  id: ID!
  """
  How many inventory units one unit of the line's unit of measure equals.
  """
  inventoryConversionFactor: Float!
  """The ID of the unit of measure the stock for this line is held in."""
  inventoryUOMId: String
  """The invoice lines that bill this line."""
  invoiceItems: [InvoiceItemInfo!]
  """Quantity already invoiced on this line."""
  invoicedQuantity: Float
  """Notes on this line."""
  notes: String
  """
  Whose price this line carries: ENGINE, CLIENT, OVERRIDE, QUOTE_CONVERSION, IMPORT, or CONVERTED (the product's base price converted at the document rate). Null on older lines.
  """
  priceSource: String
  """The product on this line."""
  product: Product
  """The ID of the product on this line."""
  productId: String!
  """The product name, as stored on the line."""
  productName: String!
  """The SKU of the variant, as stored on the line."""
  productSku: String!
  """Quantity ordered, in the line's unit of measure."""
  quantity: Float!
  """
  Quantity not yet invoiced: the line quantity (after cancellations) less invoicedQuantity.
  """
  remainingQuantity: Float
  """Not maintained; always 0."""
  returnedQuantity: Float! @deprecated(reason: "Never written; always 0. Read SalesOrder.lineReturns for what returns hold against each line.")
  """The ID of the sales order this line belongs to."""
  salesOrderId: String!
  """Quantity shipped so far."""
  shippedQuantity: Float!
  """Total tax on the line."""
  taxAmount: Float!
  """
  Tax applied to this line, as a list of { taxName, taxCode, taxType, rate, taxAmount }.
  """
  taxBreakdown: JSON
  """The ID of the tax group applied to this line."""
  taxGroupId: String
  """The tax rate applied to the line, as a percentage."""
  taxRate: Float!
  """The IDs of the tax rates applied to this line."""
  taxRateIds: [String!]
  """The line total, as calculated and stored by the server."""
  totalAmount: Float!
  """Price per unit before the line discount."""
  unitPrice: Float!
  """The ID of the unit of measure the quantity is expressed in."""
  uomId: String!
  """Name of the unit of measure."""
  uomName: String!
  """Symbol of the unit of measure."""
  uomSymbol: String!
  """When the line was last changed."""
  updatedAt: DateTime!
  """The product variant on this line."""
  variant: ProductVariant
  """The ID of the product variant on this line."""
  variantId: String
  """The variant name, as stored on the line."""
  variantName: String
  """The warehouse this line is fulfilled from."""
  warehouse: Warehouse
  """The ID of the warehouse this line is fulfilled from."""
  warehouseId: String
}

"""
The part of a sales order line that is filled from one warehouse. The quantities of a line's allocations add up to the line.
"""
type SalesOrderItemAllocation {
  """
  The quantity in base units: the quantity times the unit conversion factor.
  """
  baseQuantity: Float!
  """The batch the reservation is pinned to."""
  batchNumber: String
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """The quantity, in the order line's unit of measure."""
  quantity: Float!
  """
  How much of the allocation can still be shipped, in the order line's unit of measure.
  """
  remainingQuantity: Float
  """The ID of the stock reservation behind the allocation, if any."""
  reservationId: ID
  """Where the reservation stands."""
  reservationStatus: AllocationReservationStatus!
  """The ID of the order line."""
  salesOrderItemId: ID!
  """The serial number the reservation is pinned to."""
  serialNumber: String
  """How the allocation was made."""
  source: AllocationSource!
  """The warehouse the stock comes from."""
  warehouse: AllocationWarehouseRef
  "The ID of the warehouse."
  warehouseId: ID!
}

"""An online payment received for a sales order."""
type SalesOrderOnlinePayment {
  """Amount paid, in the order currency."""
  amount: Float
  "ISO 4217 currency code."
  currencyCode: String!
  """When the payment was received."""
  paidAt: DateTime!
  """The collection recorded for this payment, once it exists."""
  paymentId: ID
  """The payment's number."""
  paymentNumber: String
  """The payment provider that processed the payment."""
  provider: String!
  """The payment provider's reference — the Payment row's referenceNumber."""
  reference: String!
}

"""
One payment that counts toward, or is waiting to count toward, a sales order.
"""
type SalesOrderPaymentLine {
  """The part of this payment tied to the order, in the order's currency."""
  amount: Float!
  """
  True for a portal bank transfer the seller has not accepted yet; it is not counted as received.
  """
  awaitingAcceptance: Boolean!
  """
  True for the admin's own entry that is still a Draft. Confirm it to count it; it is not counted as received.
  """
  draft: Boolean!
  """The payment date."""
  paymentDate: DateTime
  """The payment's id; opens its collection page."""
  paymentId: ID!
  """The collection number, e.g. COL-202610-0047."""
  paymentNumber: String
  """The payment's status."""
  status: String
  """True when a second person or the gateway vouched for it."""
  verified: Boolean!
}

"""
What the seller has taken in against one sales order before or without an invoice, in the order's own currency. Drives the order screen's Paid and Balance.
"""
type SalesOrderPaymentSummary {
  """
  Portal bank transfers the customer registered that the seller has not accepted yet. Not counted as received.
  """
  awaitingAcceptanceAmount: Float!
  """
  Total minus received, never below zero. Recording a payment is offered while this is above zero.
  """
  balanceAmount: Float!
  """
  Whether this order may take a payment now. The same rule the payment mutations enforce for the admin, the customer apps and the MCP tools: payable status (a Draft only with Prepaid terms) and something still unpaid and unclaimed.
  """
  canRecordPayment: Boolean!
  """The order's currency code; every amount below is in it."""
  currency: String
  """
  Admin entries still in Draft, linked to the order. A claim on the balance, not money; not counted as received.
  """
  draftAmount: Float!
  """
  How far received money is above the order total (the customer over-paid, or the order was edited down after payment). Zero otherwise. The extra stays unallocated on the payment.
  """
  overpaidAmount: Float!
  """Each payment tied to the order, in the order the payments were read."""
  payments: [SalesOrderPaymentLine!]!
  """
  Money received against the order: every committed payment linked to it, verified or not. A portal transfer the seller has not accepted yet is not included. Can exceed the total when the customer over-paid.
  """
  receivedAmount: Float!
  """
  Why it cannot take a payment: ORDER_NOT_PAYABLE (status), ORDER_FULLY_PAID, or ORDER_PAYMENT_WAITING (a transfer or Draft is waiting to be accepted or confirmed). Null when it can.
  """
  recordPaymentBlockedCode: String
  """The order total."""
  totalAmount: Float!
  """
  Still unpaid and unclaimed: total minus received, minus transfers waiting for acceptance, minus Draft entries, never below zero. A payment is offered only while this is above zero.
  """
  unclaimedAmount: Float!
  """
  The part of received money that a second person or the payment gateway vouched for. This is what the Payment Before Release rule counts.
  """
  verifiedAmount: Float!
}

"""A column the sales order list can be sorted by."""
enum SalesOrderSortField {
  """The order date."""
  ORDER_DATE
  """The total amount."""
  TOTAL_AMOUNT
  """When the order was last changed."""
  UPDATED_AT
}

"""
Where a sales order stands: DRAFT, AWAITING_PAYMENT, CONFIRMED, PARTIALLY_INVOICED, INVOICED, PARTIALLY_SHIPPED, SHIPPED, DELIVERED, CANCELLED or RETURNED.
"""
enum SalesOrderStatus {
  """Waiting for payment."""
  AWAITING_PAYMENT
  """Cancelled."""
  CANCELLED
  """Confirmed."""
  CONFIRMED
  """Delivered."""
  DELIVERED
  """Being prepared."""
  DRAFT
  """Fully invoiced."""
  INVOICED
  """Some items are invoiced."""
  PARTIALLY_INVOICED
  """Some items have shipped."""
  PARTIALLY_SHIPPED
  """Returned."""
  RETURNED
  """Shipped."""
  SHIPPED
}

"""Counts and values across sales orders, for the dashboard."""
type SalesOrderSummary {
  """Orders confirmed and not yet shipped."""
  confirmedOrders: Int!
  """Orders delivered."""
  deliveredOrders: Int!
  """Orders in draft."""
  draftOrders: Int!
  """When these figures were computed."""
  lastUpdated: DateTime!
  """Orders awaiting confirmation."""
  pendingOrders: Int!
  """
  Value of committed orders not yet fully collected, in the base currency. Draft, cancelled and returned orders are excluded.
  """
  pendingPaymentsValue: Float!
  """Value of confirmed orders, in the base currency."""
  pendingValue: Float!
  """The most recently updated orders."""
  recentOrders: [SalesOrder!]!
  """Orders shipped."""
  shippedOrders: Int!
  """Value of shipped orders, in the base currency."""
  shippedValue: Float!
  """Number of sales orders."""
  totalOrders: Int!
  """Total value of all orders, in the organization's base currency."""
  totalValue: Float!
}

"""Sales results by rep."""
type SalesPerformanceAnalytics {
  """The reps, ranked."""
  leaderboard: [RepPerformance!]!
  """The signed-in user's commission totals."""
  myCommissions: RepCommissionSummary!
  """How many reps are in the team."""
  teamSize: Int!
}

"""The organization-wide sales policy."""
type SalesPolicy {
  """
  Maximum discount (%) a manual price override may imply; 100 = no ceiling
  """
  maxDiscountPercent: Float!
  """
  Ship only after invoice: an order line ships at most its invoiced quantity (false = off, the default)
  """
  requireInvoiceBeforeShip: Boolean!
}

"""One line of a sales return."""
input SalesReturnItemInput {
  """The batch number of the returned stock."""
  batchNumber: String
  """The condition the item is in."""
  condition: String!
  "The ID of the product."
  productId: String!
  """The quantity returned. Must be greater than zero."""
  quantity: Int!
  """The serial numbers of the returned units."""
  serialNumbers: [String!]
  "The ID of the product variant."
  variantId: String!
}

"""Sales settings."""
input SalesSettingsInput {
  """The default payment terms."""
  defaultPaymentTerms: String
  """The ID of the default salesperson."""
  defaultSalesperson: String
  """The default tax rate."""
  defaultTaxRate: String
  """True to allow discounts."""
  enableDiscounts: Boolean
  """True to use quotations."""
  enableQuotations: Boolean
  """The order amount above which an order counts as large."""
  largeOrderThreshold: String
  """
  The largest discount allowed, in percent. It is saved on the organization's pricing settings and enforced as a hard cap on manual prices.
  """
  maxDiscountPercent: String
  """True when large orders need approval."""
  requireApprovalForLargeOrders: Boolean
  """
  Ship only after invoice: when true, an order line ships at most its invoiced quantity (default false).
  """
  requireInvoiceBeforeShip: Boolean
}

"""
One finding for a customer, from the same attention list the customer's Insights tab shows.
"""
type SalesSignalRow {
  """The facts behind the finding."""
  evidence: [CustomerEvidence!]!
  """What was found."""
  headline: String!
  """The key of the rule that found it."""
  key: String!
  """
  The latest order, cart touch, open invoice or buyer sign in in the period.
  """
  lastActivityAt: DateTime
  "The ID of the partner."
  partnerId: ID!
  """The name of the customer."""
  partnerName: String!
  """The customer's assigned rep. Empty when nobody owns the account."""
  repName: String
  """The rule that found it, in words."""
  ruleText: String!
  """How serious it is."""
  severity: String!
  """
  The money at stake, in the organization's base currency. Empty when there is none.
  """
  stake: Float
}

"""The Sales signals list: findings across customers."""
type SalesSignals {
  """
  The rule keys present in the unfiltered list, for the signal type filter.
  """
  availableKeys: [String!]!
  """How many customers with activity in the period were checked."""
  customersEvaluated: Int!
  """The requested page of the ranked, filtered list."""
  rows: [SalesSignalRow!]!
  """Whose customers are covered."""
  scope: AnalyticsScope!
  """How many rows match the filter, before paging."""
  total: Int!
  """
  True when more customers had activity than one list checks. The most recently active were kept.
  """
  truncated: Boolean!
}

"""Filters for the Sales signals list."""
input SalesSignalsFilterInput {
  """
  Only findings with at least this much money at stake, in the base currency. 0 means any finding that has money at stake.
  """
  minStake: Float
  "Text to search for."
  search: String
  """
  Only findings from these rules, for example cart_idle or invoices_overdue. Empty means all.
  """
  signalKeys: [String!]
}

"""Which page of the Sales signals list to return."""
input SalesSignalsPageInput {
  "Maximum number of records to return."
  limit: Int! = 25
  "Number of records to skip before the first one returned."
  offset: Int! = 0
}

"""A control to create, or the new rule for an existing one."""
input SaveControlInput {
  """The checkpoint the control runs at."""
  checkpoint: String!
  """The conditions, at most ten."""
  conditions: [ControlConditionInput!]!
  """
  The control version you last read. An update is refused if someone else changed it since.
  """
  expectedVersion: Int
  """The ID of the control to update. Leave empty to create one."""
  id: ID
  """all: every condition must match; any: one is enough."""
  join: String!
  """
  off to create the control switched off. A new control otherwise starts in observe; an update keeps its mode.
  """
  mode: String
  """The control's name."""
  name: String!
  """What happens when the conditions match."""
  outcome: ControlOutcomeInput!
  """The preset the control was created from, if any."""
  presetId: String
  """Why the change was made, kept in the history."""
  reason: String
  """The customers and warehouses the control covers."""
  scope: ControlScopeInput
}

"""Saves how to read a supplier's price list."""
input SaveCopilotSupplierRuleInput {
  """Which column of the file feeds each product field."""
  columnMap: JSON
  """How to work out the minimum order quantity."""
  moqRule: String
  """How to work out the price."""
  priceRule: String
  """The name of the supplier."""
  supplierName: String!
}

"""
Input to save an email draft. Every field is optional so a draft can be saved half written.
"""
input SaveDraftInput {
  """The email body as HTML."""
  bodyHtml: String
  """Addresses to copy."""
  ccEmails: [String!]
  """Draft ID to update (omit for new draft)"""
  id: ID
  """The ID of the email this draft replies to."""
  inReplyToId: ID
  """The ID of the document the draft relates to."""
  referenceId: ID
  """Type of document the draft relates to."""
  referenceType: EmailReferenceType
  """Subject line."""
  subject: String
  """Recipient addresses."""
  toEmails: [String!]
  """Kind of draft (for example a new email, a reply or a forward)."""
  type: String = "COMPOSE"
}

"""Saves a mapping profile."""
input SaveImportMappingProfileInput {
  """
  Which source column header feeds each product field. It is checked against the known fields.
  """
  fieldMap: JSON!
  """The ID of the profile to update. Leave out to create one."""
  id: String
  "Whether the record is active."
  isActive: Boolean
  """The name of the profile."""
  name: String!
  """The supplier the profile is for."""
  supplierName: String
}

"""Saves the storefront theme draft."""
input SaveStorefrontDraftInput {
  """The draft theme, as JSON."""
  draft: JSON!
  """
  The stored draft's updatedAt as this editor last read or saved it. The save is refused with VERSION_CONFLICT when the draft was saved since; null when the editor found no draft (create only). Omit only from a client that cannot know it: the save then overwrites.
  """
  expectedUpdatedAt: DateTime
}

"""A pickup of returned goods."""
input SchedulePickupInput {
  """The address to collect from."""
  address: String
  """
  A courier to book for the pickup. Needs the sales:shipment:create permission and the deliveryPartners plan feature. Leave out to only record the pickup.
  """
  delivery: ShipmentBookingInput
  """Instructions for the pickup."""
  instructions: String
  """The date of the pickup."""
  pickupDate: String
}

"""Search suggestions for a query."""
type SearchSuggestResponse {
  """The text that was searched."""
  query: String!
  """The suggestions."""
  suggestions: [SearchSuggestion!]!
}

"""One search suggestion."""
type SearchSuggestion {
  """Internal route path or null to fill the search box only."""
  href: String
  "The unique ID of this record."
  id: ID!
  """The URL of an image."""
  imageUrl: String
  """What the suggestion is."""
  kind: SearchSuggestionKind!
  """The text of the suggestion."""
  label: String!
}

"""
What a search suggestion is: a QUERY, CATEGORY, PRODUCT, BRAND or VARIANT.
"""
enum SearchSuggestionKind {
  """A brand."""
  BRAND
  """A category."""
  CATEGORY
  """A product."""
  PRODUCT
  """A popular search phrase."""
  QUERY
  """A product variant."""
  VARIANT
}

"""How sales behave in one season."""
type SeasonalTrend {
  """The average sales in the season."""
  averageSales: Float!
  """The month with the highest sales."""
  peakMonth: String!
  """The season."""
  season: String!
}

"""A home section showing a secondary advertisement."""
type SecondaryAdSection {
  """Where the advertisement leads."""
  href: String
  """The URL of the advertisement image."""
  imageUrl: String
  """The kind of home section."""
  kind: HomeSectionKind!
  """The subtitle of the advertisement."""
  subtitle: String
  """The title of the advertisement."""
  title: String
}

"""Security settings."""
input SecuritySettingsInput {
  """The email domains allowed to sign up."""
  allowedDomains: String
  """True to keep an audit log."""
  enableAuditLog: Boolean
  """True to allow single sign on."""
  enableSSOLogin: Boolean
  """True to offer two-factor sign in."""
  enableTwoFactor: Boolean
  """True to force users to change their password."""
  forcePasswordChange: Boolean
  """The IP addresses allowed to sign in."""
  ipWhitelist: String
  """The password rules."""
  passwordPolicy: String
  """True to require sensitive exports to be encrypted."""
  requireEncryptedExports: Boolean
  """How long a session lasts."""
  sessionTimeout: String
}

"""The result of creating empty stock rows for a warehouse."""
type SeedInventoryResponse {
  """How many stock rows were created."""
  created: Int!
  """How many already existed and were skipped."""
  skipped: Int!
  """How many variants were considered."""
  total: Int!
  "The ID of the warehouse."
  warehouseId: String!
  """The name of the warehouse."""
  warehouseName: String!
}

"""Whether a message may be sent now, and if not why."""
type SendEligibilityGql {
  """True when the message may be sent."""
  allowed: Boolean!
  """
  When allowed but held to the next send window, the time it will go out.
  """
  deferredUntil: DateTime
  """
  A machine-readable reason when not allowed, for example NO_CONSENT or OPTED_OUT.
  """
  reason: String
  """A plain reason to show next to a disabled action."""
  reasonText: String
}

"""The result of sending an email."""
type SendEmailResult {
  """The ID of the activity record for the email."""
  emailActivityId: String
  """Why it failed, if it did."""
  error: String
  """A message about the outcome."""
  message: String!
  """The email provider's ID for the message."""
  messageId: String
  """The address replies will go to."""
  replyToAddress: String
  """True when the email was sent."""
  success: Boolean!
}

"""The organization's rules for sending marketing messages."""
type SendGovernorSettingsGql {
  """The most marketing messages one customer may get per day."""
  dailyCapPerPartner: Int!
  """True when marketing messages may be sent at all."""
  marketingEnabled: Boolean!
  """The hour the send window closes."""
  sendWindowCloseHour: Int!
  """The hour the send window opens."""
  sendWindowOpenHour: Int!
  """The most marketing messages one contact may get per week."""
  weeklyCapPerContact: Int!
}

"""
A quote email to send: the quote, the To, Cc and Bcc recipients, and the subject and message.
"""
input SendQuoteEmailInput {
  """Bcc recipients (never shown on the activity row's To/Cc)."""
  bccEmails: [String!]
  """Cc recipients."""
  ccEmails: [String!]
  """Additional message to include in email body"""
  customMessage: String
  """Custom email subject (optional)"""
  customSubject: String
  """
  Primary recipient (legacy single-address form). Use toEmails for several; at least one To is required.
  """
  customerEmail: String
  """The ID of the quote to email."""
  quoteId: ID!
  """PDF template override (PROFESSIONAL, MODERN, MINIMAL)"""
  templateOverride: String
  """To recipients (merged with customerEmail, de-duplicated)."""
  toEmails: [String!]
}

"""Result of sending a quote by email."""
type SendQuoteEmailResult {
  """The ID of the recorded email activity."""
  emailActivityId: String
  """The reason it failed. Null on success."""
  error: String
  """The provider's ID for the message."""
  messageId: String
  """The address customer replies are routed to."""
  replyToAddress: String
  """Whether the email was accepted for sending."""
  success: Boolean!
}

"""A reply to a customer's email on a quote."""
input SendQuoteReplyInput {
  """Reply message body (plain text)"""
  body: String!
  """CC email addresses"""
  ccEmails: [String!]
  """Override subject (defaults to Re: original subject)"""
  customSubject: String
  """ID of the email being replied to"""
  inReplyToActivityId: ID!
  """The ID of the quote the reply belongs to."""
  quoteId: ID!
  """Override recipient email (defaults to original sender)"""
  toEmail: String
}

"""A reply to an email on a sales order."""
input SendSalesOrderReplyInput {
  """The reply message, as plain text."""
  body: String!
  """CC email addresses."""
  ccEmails: [String!]
  """
  Override the subject. Defaults to Re: followed by the original subject.
  """
  customSubject: String
  """The ID of the email being replied to."""
  inReplyToActivityId: ID!
  """The ID of the sales order the reply belongs to."""
  salesOrderId: ID!
  """Override the recipient. Defaults to the original sender."""
  toEmail: String
}

"""Sends a test WhatsApp message."""
input SendWhatsAppTestMessageInput {
  """
  The values for the template's variables, in order. They are sent exactly as given, so the count must match the template.
  """
  bodyValues: [String!]
  """
  Which provider's setup sends the test. Leave out to use the enabled one, else the latest.
  """
  provider: WhatsAppProvider
  """The phone number to send to."""
  toPhone: String!
  """The trigger whose template to test."""
  triggerKey: String
}

"""A session of the signed-in user."""
type SessionInfo {
  """The browser."""
  browser: String
  "When the record was created."
  createdAt: DateTime!
  """The device."""
  device: String
  "The unique ID of this record."
  id: ID!
  """The IP address."""
  ipAddress: String!
  "Whether the record is active."
  isActive: Boolean!
  """True when this is the session in use now."""
  isCurrent: Boolean!
  """When the session was last active."""
  lastActivityAt: DateTime!
  """Where it came from."""
  location: String
  """The operating system."""
  os: String
  """The browser or app string."""
  userAgent: String
}

"""Sets the organization's base currency."""
input SetBaseCurrencyInput {
  "ISO 4217 currency code."
  currencyCode: String!
}

"""Sets delivery directions on the cart."""
input SetCartDirectionsInput {
  """The directions for the delivery."""
  directions: String!
}

"""Sets the commission rate of a role."""
input SetCommissionRoleRateInput {
  "Whether the record is active."
  isActive: Boolean
  """The rate, in percent."""
  rate: Float!
  """The role."""
  role: String!
}

"""Switch a control off, to observe, or to enforce."""
input SetControlModeInput {
  """The ID of the control."""
  id: ID!
  """off, observe or enforce."""
  mode: String!
  """
  Why the change was made, kept in the history. Required, and not blank, to switch to enforce; optional for observe and off.
  """
  reason: String
}

"""Turn the controls kill switch on or off."""
input SetControlsKillSwitchInput {
  """True: every control observes."""
  active: Boolean!
  """Why, 3 to 500 characters."""
  reason: String!
}

"""
Sets whether a customer's approvers act for the whole company or one branch.
"""
input SetCustomerApproverScopeInput {
  """
  Required (≥1) when scope = BRANCH; ignored under COMPANY. Full-array replace.
  """
  addressIds: [ID!]
  """COMPANY for the whole company, BRANCH for one branch."""
  scope: CustomerApproverScope!
  "The ID of the user."
  userId: ID!
}

"""Sets the commission rate for a customer."""
input SetCustomerCommissionRateInput {
  "Whether the record is active."
  isActive: Boolean
  "The ID of the partner."
  partnerId: String!
  """The rate, in percent."""
  rate: Float!
}

"""Pins a customer to a tier by hand."""
input SetCustomerTierOverrideInput {
  "The ID of the customer."
  customerId: String!
  """
  The tier to pin the customer to, which stops automatic tiering from moving it. Leave out or send null to clear the pin.
  """
  tierKey: String
}

"""Sets the domain the organization sends mail from."""
input SetEmailSenderDomainInput {
  """The domain."""
  domain: String!
}

"""Saves the guided flows. They replace the saved ones."""
input SetGuidedFlowsInput {
  """The flows."""
  flows: JSON!
}

"""Sets or clears the picture of one product attribute value."""
input SetProductAttributeValueImageInput {
  """The attribute, in any spelling."""
  attributeKey: String!
  """
  The picture's URL, from the upload endpoint or https. Null or empty clears it.
  """
  imageUrl: String
  """The value as variants carry it."""
  value: String!
}

"""Sets a rep's default commission rate."""
input SetRepCommissionRateInput {
  """The rate, in percent."""
  defaultRate: Float!
  "Whether the record is active."
  isActive: Boolean
  "The ID of the user."
  userId: String!
}

"""A manual warehouse split for one sales order line."""
input SetSalesOrderItemAllocationsInput {
  """The ID of the order line to split."""
  salesOrderItemId: ID!
  """
  How the line is split across warehouses. The quantities must add up to the line quantity.
  """
  splits: [AllocationSplitInput!]!
}

"""A record of one change to a setting."""
type SettingAudit {
  """What was done."""
  action: SettingAuditAction!
  "The unique ID of this record."
  id: ID!
  """The IP address the change came from."""
  ipAddress: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The data type after."""
  newDataType: String
  """The value after."""
  newValue: JSON
  """The data type before."""
  oldDataType: String
  """The value before."""
  oldValue: JSON
  "The ID of the organization the record belongs to."
  organizationId: String!
  """When it was changed."""
  performedAt: DateTime!
  """The ID of the user who changed it."""
  performedBy: String!
  """The name of the user who changed it."""
  performedByName: String
  """Why it was changed."""
  reason: String
  """The group the setting is in."""
  settingCategory: String!
  """The ID of the setting."""
  settingId: String
  """The key of the setting."""
  settingKey: String!
  """The browser or app the change came from."""
  userAgent: String
}

"""Actions that can be performed on settings"""
enum SettingAuditAction {
  """Several settings were changed together."""
  BULK_UPDATE
  """A setting was created."""
  CREATE
  """A setting was removed."""
  DELETE
  """Settings were brought in from a file."""
  IMPORT
  """A setting was reset to its default."""
  RESET_TO_DEFAULT
  """A setting was changed."""
  UPDATE
}

"""Categories for organizing settings"""
enum SettingCategory {
  """Accounting."""
  ACCOUNTING
  """API access."""
  API
  """Look and feel."""
  APPEARANCE
  """Backups."""
  BACKUP
  """Company details."""
  COMPANY
  """Customer relationship management."""
  CRM
  """Currencies."""
  CURRENCY
  """Custom settings."""
  CUSTOM
  """Customer tiers."""
  CUSTOMER_TIERS
  """Documents and numbering."""
  DOCUMENTS
  """Email."""
  EMAIL
  """Inventory."""
  INVENTORY
  """Languages."""
  LANGUAGE
  """Marketing."""
  MARKETING
  """Notifications."""
  NOTIFICATIONS
  """User preferences."""
  PREFERENCES
  """Purchasing."""
  PURCHASE
  """Regional formats."""
  REGIONAL
  """Sales."""
  SALES
  """Security."""
  SECURITY
  """System."""
  SYSTEM
  """Users."""
  USER
  """Warehouses."""
  WAREHOUSE
  """Webhooks."""
  WEBHOOKS
  """Workflows."""
  WORKFLOWS
}

"""Data types for setting values"""
enum SettingDataType {
  """A list of values."""
  ARRAY
  """True or false."""
  BOOLEAN
  """A JSON object."""
  JSON
  """A number."""
  NUMBER
  """Text."""
  STRING
}

"""A group of settings."""
type SettingsGroup {
  """The group."""
  category: SettingCategory!
  """How many settings it has."""
  count: Int!
  """What the group covers."""
  description: String
  """The name to show."""
  displayName: String!
  """The settings."""
  settings: [TenantSetting!]!
}

"""Headline figures about the settings."""
type SettingsSummary {
  """How many are active."""
  activeSettings: Int!
  """How many were set by the organization rather than left at the default."""
  customSettings: Int!
  """The settings by group."""
  groups: [SettingsGroup!]!
  """When a setting last changed."""
  lastUpdated: DateTime!
  """How many settings there are."""
  totalSettings: Int!
}

"""The stock an allocation ships from."""
input ShipSalesOrderAllocationInput {
  """The ID of the warehouse allocation to ship from."""
  allocationId: ID!
  """Quantity to ship, in the order line's unit. Must be greater than zero."""
  quantity: Float!
}

"""Input to ship a sales order."""
input ShipSalesOrderInput {
  """
  Exactly which allocations to ship, and how much from each. Preferred for lines split across warehouses.
  """
  allocations: [ShipSalesOrderAllocationInput!]
  """
  Book a delivery partner as part of this shipment. If the carrier refuses, the order is left untouched.
  """
  delivery: ShipmentBookingInput
  """
  The version of the order you last read. The shipment is refused if someone else changed it since.
  """
  expectedVersion: Int
  """Not used: the order id is the mutation's own id argument."""
  id: ID
  """
  A unique key you generate. Retrying with the same key replays the original shipment instead of shipping twice.
  """
  idempotencyKey: String
  """
  Quantity to ship per line, spread over that line's reserved allocations oldest first. Ignored when allocations is set.
  """
  items: [ShipSalesOrderItemInput!]
  """Notes to record on the shipment."""
  notes: String
  """Carrier tracking number to record on the shipment."""
  trackingNumber: String
}

"""A line being shipped on a sales order."""
input ShipSalesOrderItemInput {
  """The ID of the order line to ship."""
  itemId: ID!
  """Quantity to ship for this line."""
  shippedQuantity: Float!
}

"""
The delivery booking details sent with a ship: the delivery partner, the selected rate, the parcels, the recipient and the pickup window.
"""
input ShipmentBookingInput {
  """
  Ship command only: also make the selected rate the order's shipping charge. The server prices the selection itself, and refuses the ship, with nothing booked and no stock moved, when the charge may not change.
  """
  applyRateToOrderShipping: Boolean
  """The carrier's name."""
  carrierName: String
  """The ID of the delivery partner configuration to book with."""
  deliveryPartnerConfigId: ID!
  """Notes for the booking. At most 1000 characters."""
  notes: String
  """
  The parcels to book. Without parcels, each shipment is packed on its own.
  """
  parcels: [DeliveryParcelInput!]
  """End of the pickup window."""
  pickupWindowEnd: DateTime
  """Start of the pickup window."""
  pickupWindowStart: DateTime
  """The provider's reference for the selected rate."""
  providerQuoteRef: String
  """
  The rate staff picked, which is the seller's cost, as a decimal string. The server prices the selection itself; this amount is never charged as sent.
  """
  quotedAmount: String
  """ISO 4217 currency code of quotedAmount."""
  quotedCurrency: String
  """
  The parcels the selected rate was priced for (the rate option's parcels). Without `parcels`, each shipment is packed on its own and books these only when it still packs to them; otherwise it books its own boxes without the quote reference and amount.
  """
  quotedParcels: [DeliveryParcelInput!]
  """Who the shipment is delivered to."""
  recipient: ShipmentRecipientInput
  """The carrier's service level code."""
  serviceLevelCode: String
  """The carrier's service level name."""
  serviceLevelName: String
  """
  For custom couriers: the tracking number from the courier. At most 120 characters.
  """
  trackingNumber: String
}

"""
Staff only (needs sales:sales_order:ship): what this shipment's courier charged at booking and how it was split between the customer (their billed shipping share) and the seller. Decimal strings in `currency`.
"""
type ShipmentCostSplit {
  """When the courier was changed."""
  changedAt: DateTime
  """Who changed the courier on the order."""
  changedByName: String
  """What the courier charged for the shipment at booking."""
  courierCharge: String!
  "ISO 4217 currency code."
  currency: String!
  """The customer's original choice."""
  customerChose: ShipmentCostSplitCustomerChoice
  """
  The part of the customer's shipping charge that falls on this shipment.
  """
  customerPaid: String!
  """
  The planned courier charge for the shipment when staff changed the courier. Empty without a plan.
  """
  plannedCost: String
  """
  Who pays the difference under the order's courier plan. Empty without a plan.
  """
  policy: CourierCostPolicy
  """Why the seller pays. Required when the seller's share is above zero."""
  reason: String
  """
  The courier charge minus what the customer paid. Negative when the customer paid more than the courier charged.
  """
  sellerPaid: String!
  """
  The courier charge minus the planned cost. Negative when it was cheaper than planned. Empty without a plan.
  """
  variance: String
}

"""
The delivery option the customer first chose, as the cost split shows it.
"""
type ShipmentCostSplitCustomerChoice {
  """What the customer agreed to pay for shipping, as a decimal string."""
  amount: String!
  "ISO 4217 currency code."
  currency: String!
  """
  The courier and service, for example Courier · Service. Empty when the order had no named choice.
  """
  label: String
}

"""
Staff only (needs sales:sales_order:ship): the seller recorded paying the courier for this shipment. Recording only — the payment and its accounting stay in the seller's bank and accounting tools.
"""
type ShipmentCourierPayment {
  """How it was paid, for example EFT, Card, Cash or Courier account."""
  method: String!
  """The date the courier was paid, as YYYY-MM-DD."""
  paidOn: String!
  """When the payment was recorded."""
  recordedAt: DateTime
  """The ID of the user who recorded it."""
  recordedById: String!
  """The name of the user who recorded it."""
  recordedByName: String
  """The bank or courier reference. May be empty."""
  reference: String!
}

"""
Whether the seller has paid the courier for a shipment (staff only): PAID (Mark Courier Paid recorded it), UNPAID, NOT_APPLICABLE (cancelled, or the booking failed — nothing is owed).
"""
enum ShipmentCourierPaymentStatus {
  """No courier payment is due."""
  NOT_APPLICABLE
  """The courier has been paid."""
  PAID
  """The courier has not been paid."""
  UNPAID
}

"""
The delivery option the customer chose at checkout, as saved on the order, so the ship dialog can preselect it. It never carries the provider's quote reference or keys.
"""
type ShipmentCustomerChoice {
  """
  What the customer agreed to at checkout, as a decimal string exactly as saved on the order.
  """
  amount: String!
  """The courier the customer chose."""
  carrierName: String!
  """
  How the customer chose: LIST, SPEEDS or AUTO. Empty on orders placed before the setting existed.
  """
  choiceMode: DeliveryChoiceMode
  "ISO 4217 currency code."
  currency: String!
  """The ID of the delivery partner the customer's option came from."""
  deliveryPartnerConfigId: String!
  """
  The parcels the customer's price was quoted for (cm / kg) — book these with the customer's choice. Null on orders quoted before box packing.
  """
  parcels: [DeliveryParcelGql!]
  """The partner's name now. Empty when the partner no longer exists."""
  partnerDisplayName: String
  """When the customer's price was quoted."""
  quotedAt: DateTime!
  """The code of the service level the customer chose."""
  serviceLevelCode: String!
  """The name of the service level the customer chose."""
  serviceLevelName: String!
  """The ID of the speed the customer picked, in SPEEDS mode."""
  speedId: String
  """The name of the speed as the customer saw it."""
  speedName: String
}

"""
Which way a shipment goes: OUTBOUND to a customer or RETURN back from one.
"""
enum ShipmentDirection {
  """Goods going to the customer."""
  OUTBOUND
  """Goods coming back from the customer."""
  RETURN
}

"""One step on a shipment's timeline."""
type ShipmentEventGql {
  """What happened."""
  description: String
  "The unique ID of this record."
  id: ID!
  """Where it happened."""
  location: String
  """When it happened."""
  occurredAt: DateTime!
  """The carrier's own status text."""
  rawStatus: String
  """Where the event came from: WEBHOOK, POLL, MANUAL or SYSTEM."""
  source: String!
  """The status of the shipment at this point."""
  status: ShipmentStatus!
  """
  False when the carrier's status could not be mapped: `status` is then the shipment's status at that moment, not the carrier's — show rawStatus instead.
  """
  statusMapped: Boolean
}

"""
A shipment as staff see it. It includes the seller's cost and is never returned to buyers.
"""
type ShipmentGql {
  """
  Staff only: the numbers of the order's live sales invoices (not cancelled or voided) that bill its shipping — the shipment's "Billed on". Null unless the caller holds sales:sales_order:ship, and for a return pickup.
  """
  billedInvoiceNumbers: [String!]
  """When the shipment was booked."""
  bookedAt: DateTime
  """When the shipment was cancelled."""
  cancelledAt: DateTime
  """The partner's logo, or empty to show a monogram."""
  carrierLogoUrl: String
  """The courier carrying the shipment."""
  carrierName: String!
  """The seller's final cost, as a decimal string."""
  chargedCost: String
  """
  Staff only: the shipment's cost split (customer paid / courier charge / seller paid). Null unless the caller holds sales:sales_order:ship, or when no split was recorded (the charge was not known at booking).
  """
  costSplit: ShipmentCostSplit
  """
  Staff only: the recorded courier payment. Null unless the caller holds sales:sales_order:ship, or when none is recorded.
  """
  courierPayment: ShipmentCourierPayment
  """
  Staff only: PAID / UNPAID / NOT_APPLICABLE. Null unless the caller holds sales:sales_order:ship.
  """
  courierPaymentStatus: ShipmentCourierPaymentStatus
  "When the record was created."
  createdAt: DateTime!
  "ISO 4217 currency code."
  currency: String!
  """When the shipment was delivered."""
  deliveredAt: DateTime
  """The ID of the delivery partner the shipment is booked with."""
  deliveryPartnerConfigId: String
  """The address the shipment is delivered to."""
  destinationAddress: JSON!
  """OUTBOUND for an order delivery, RETURN for a return pickup."""
  direction: ShipmentDirection!
  """The provider's exact error, if there was one."""
  errorMessage: String
  """When the shipment is expected to arrive."""
  estimatedDeliveryAt: DateTime
  """The timeline of the shipment."""
  events: [ShipmentEventGql!]!
  """True when a shipping label is available."""
  hasLabel: Boolean!
  """True when proof of delivery is available."""
  hasProofOfDelivery: Boolean!
  "The unique ID of this record."
  id: ID!
  """The lines of the shipment."""
  items: [ShipmentItemGql!]!
  """
  True while a courier is carrying the shipment and the carrier reports a live position.
  """
  liveLocationAvailable: Boolean!
  """True for a custom courier, whose status staff record by hand."""
  manualStatus: Boolean!
  """The address the shipment is collected from."""
  originAddress: JSON!
  """The ID of the warehouse the shipment leaves."""
  originWarehouseId: String
  """The parcels of the shipment."""
  parcels: [DeliveryParcelGql!]!
  """When the courier collected the parcel."""
  pickedUpAt: DateTime
  """What the courier reported about the pickup. Empty until it reports."""
  pickup: ShipmentPickup
  """True when the pickup window closed and the courier did not collect."""
  pickupMissed: Boolean!
  """The end of the pickup window staff booked."""
  pickupWindowEnd: DateTime
  """The start of the pickup window staff booked."""
  pickupWindowStart: DateTime
  """The ID of the return, for a return pickup."""
  productReturnId: String
  """The provider key of the delivery partner."""
  providerKey: String!
  """The seller's cost at booking, as a decimal string."""
  quotedCost: String
  """The carrier's own status text."""
  rawStatus: String
  """Who the shipment is delivered to."""
  recipient: JSON!
  "The ID of the sales order."
  salesOrderId: String
  """The code of the service level."""
  serviceLevelCode: String
  """The name of the service level."""
  serviceLevelName: String
  """The shipment number."""
  shipmentNumber: String!
  """The status of the shipment."""
  status: ShipmentStatus!
  """The carrier's tracking number."""
  trackingNumber: String
  """A link to track the shipment with the carrier."""
  trackingUrl: String
}

"""One line of a shipment."""
type ShipmentItemGql {
  """The ID of the warehouse allocation the item is shipped from."""
  allocationId: String
  """What is shipped."""
  description: String
  "The unique ID of this record."
  id: ID!
  """The ID of the return line, for a return pickup."""
  productReturnItemId: String
  """The quantity shipped."""
  quantity: Float!
  """The ID of the order line the item comes from."""
  salesOrderItemId: String
}

"""Narrows the shipments list. Every field is optional."""
input ShipmentListFilterInput {
  """
  Staff only (needs sales:sales_order:ship): shipments whose courier is PAID, UNPAID or NOT_APPLICABLE (cancelled / booking failed).
  """
  courierPayment: ShipmentCourierPaymentStatus
  """Only shipments created on or after this moment."""
  dateFrom: DateTime
  """Only shipments created on or before this moment."""
  dateTo: DateTime
  """
  OUTBOUND for order deliveries, RETURN for return pickups. Leave out for both.
  """
  direction: ShipmentDirection
  """
  AWAITING for a pickup that is booked and still due, MISSED for a courier who did not collect in the window.
  """
  pickup: ShipmentPickupFilter
  "Text to search for."
  search: String
  """One tab of the list. Leave out for every status."""
  statusGroup: ShipmentStatusGroup
}

"""One page of the shipments list."""
type ShipmentListPage {
  """The shipments on this page."""
  items: [ShipmentListRow!]!
  """How many shipments match the filter, over all pages."""
  total: Int!
}

"""One row of the shipments list."""
type ShipmentListRow {
  """When the shipment was booked."""
  bookedAt: DateTime
  """When the shipment was cancelled."""
  cancelledAt: DateTime
  """The partner's logo, or empty to show a monogram."""
  carrierLogoUrl: String
  """The courier carrying the shipment."""
  carrierName: String!
  """The currency of the cost amounts. Only set for staff who may ship."""
  costCurrency: String
  """
  What the courier charged, as a decimal string. Only set for staff who may ship.
  """
  courierCharge: String
  """How the courier was paid. Empty when unpaid or not visible."""
  courierPaymentMethod: String
  """
  Whether the courier is PAID, UNPAID or NOT_APPLICABLE. Only set for staff who may ship.
  """
  courierPaymentStatus: ShipmentCourierPaymentStatus
  "When the record was created."
  createdAt: DateTime!
  "The ID of the customer."
  customerId: ID
  """
  The customer on the order, or for a return pickup the customer on the return.
  """
  customerName: String
  """What the customer paid towards it. Only set for staff who may ship."""
  customerPaid: String
  """When the shipment was delivered."""
  deliveredAt: DateTime
  """OUTBOUND for an order delivery, RETURN for a return pickup."""
  direction: ShipmentDirection!
  """The provider's exact error on a booking problem."""
  errorMessage: String
  """When the shipment is expected to arrive."""
  estimatedDeliveryAt: DateTime
  "The unique ID of this record."
  id: ID!
  """When the carrier or staff last reported."""
  lastEventAt: DateTime
  """
  The number of the sales order. For a return pickup, the original order when there is one.
  """
  orderNumber: String
  """When the courier collected the parcel."""
  pickedUpAt: DateTime
  """True when the pickup window closed and the courier did not collect."""
  pickupMissed: Boolean!
  """The end of the pickup window staff booked."""
  pickupWindowEnd: DateTime
  """The start of the pickup window staff booked."""
  pickupWindowStart: DateTime
  """The ID of the return, for a return pickup."""
  productReturnId: ID
  """The number of the return, for a return pickup."""
  returnNumber: String
  "The ID of the sales order."
  salesOrderId: ID
  """What the seller absorbed. Only set for staff who may ship."""
  sellerPaid: String
  """The name of the service level."""
  serviceLevelName: String
  """The shipment number."""
  shipmentNumber: String!
  """The status of the shipment."""
  status: ShipmentStatus!
  """The list tab the shipment falls under."""
  statusGroup: ShipmentStatusGroup!
  """The carrier's tracking number."""
  trackingNumber: String
  """A link to track the shipment with the carrier."""
  trackingUrl: String
}

"""
The courier's last reported position for a shipment on its way (WGS-84 degrees). Read on demand from the carrier and reused for up to 15 seconds.
"""
type ShipmentLiveLocation {
  """The courier carrying the shipment."""
  carrierName: String!
  """The latitude of the courier."""
  latitude: Float!
  """The longitude of the courier."""
  longitude: Float!
  """When the carrier last reported this position."""
  updatedAt: DateTime!
}

"""
How staff resolve a shipment whose booking needs checking with the courier. Neither calls the carrier.
"""
enum ShipmentOrphanResolution {
  """The courier did book the shipment; keep it."""
  CONFIRM_BOOKED
  """The courier did not book it; cancel it."""
  MARK_CANCELLED
}

"""
One box of a booked shipment and what is in it (the contents frozen at booking, or re-packed when that reproduces the parcels sent), with a suggested arrangement drawn with today's box and product sizes. Staff only; no cost.
"""
type ShipmentPackedBox {
  """The box id; null for an own-packaging / oversize item parcel."""
  boxId: String
  """Holds fragile items only."""
  fragile: Boolean!
  """The parcel's height as sent, in centimetres."""
  heightCm: Float!
  """What is in the box."""
  items: [ShipmentPackedBoxItem!]!
  """
  A suggested arrangement of the contents; null for a repeat of an earlier identical box (see layoutSameAsIndex) and past the drawing limit.
  """
  layout: PackedBoxLayout
  """
  For a box with the same contents as an earlier box of the shipment: that box's 0-based index, whose layout this one shares. Null otherwise.
  """
  layoutSameAsIndex: Int
  """The parcel's length as sent, in centimetres."""
  lengthCm: Float!
  """The name of the box."""
  name: String!
  """Contents + the box itself, in kilograms."""
  weightKg: Float!
  """The parcel's width as sent, in centimetres."""
  widthCm: Float!
}

"""
One item of a shipment's packed box, with its size and weight per unit as known today.
"""
type ShipmentPackedBoxItem {
  """Per unit, today; null when unknown."""
  heightCm: Float
  """Per unit, today; null when unknown."""
  lengthCm: Float
  """Product name · variant."""
  name: String!
  """Base units."""
  quantity: Float!
  """Where the size came from."""
  sizeSource: PackingValueSource!
  """The variant's SKU."""
  sku: String
  """The product variant."""
  variantId: ID!
  """Per unit, today; 0 when unknown."""
  weightKg: Float!
  """Per unit, today; null when unknown."""
  widthCm: Float
}

"""
What the courier reported about the pickup: who is coming and the pickup code. Staff only.
"""
type ShipmentPickup {
  """The name of the courier who is coming."""
  courierName: String
  """How to reach the courier, as the provider gives it."""
  courierPhone: String
  """When the courier is expected at the pickup address."""
  etaAt: DateTime
  "When the record was last changed."
  updatedAt: DateTime
  """The courier's vehicle."""
  vehicle: String
  """The code to check at pickup."""
  verificationCode: String
}

"""
AWAITING: a pickup is booked and still due. MISSED: the pickup window closed (plus a grace period) and the courier has not collected.
"""
enum ShipmentPickupFilter {
  """A pickup is booked and still due."""
  AWAITING
  """The pickup window closed and the courier has not collected."""
  MISSED
}

"""
DONE: reached and passed. CURRENT: the shipment's current step. UPCOMING: not reached yet.
"""
enum ShipmentProgressState {
  """The step the shipment is at now."""
  CURRENT
  """A step already passed."""
  DONE
  """A step not yet reached."""
  UPCOMING
}

"""
One step of the tracking stepper. `at` is when the step was first reached (null when not reached, or not known).
"""
type ShipmentProgressStep {
  """When the step happened. Empty until it does."""
  at: DateTime
  """Whether the step is done, current or upcoming."""
  state: ShipmentProgressState!
  """The step of the delivery."""
  step: ShipmentProgressStepKey!
}

"""
One step of a shipment's journey, in order: BOOKED, PICKED_UP (collected), IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERED.
"""
enum ShipmentProgressStepKey {
  """The shipment is booked with the courier."""
  BOOKED
  """The shipment is delivered."""
  DELIVERED
  """The shipment is on its way."""
  IN_TRANSIT
  """The shipment is out for delivery."""
  OUT_FOR_DELIVERY
  """The courier picked up the shipment."""
  PICKED_UP
}

"""
One order line and how much of it ships now, for a partial shipment's rate preview.
"""
input ShipmentRateLineInput {
  """
  The quantity that ships now, in the line's own unit. At most what is left to ship.
  """
  quantity: Float!
  """The ID of the order line."""
  salesOrderItemId: ID!
}

"""A price a delivery partner quoted for a shipment."""
type ShipmentRateOptionGql {
  """The price, as a decimal string in the rate's currency."""
  amount: String!
  """
  The price before the carrier's tax, as a decimal string. Only set when the partner reports it in the same currency.
  """
  amountExclTax: String
  """
  How many parcels this price is for; null when the parcels were given with the request.
  """
  boxCount: Int
  """
  Which packing won this service (the cheaper of the two candidates); null when the parcels were given with the request.
  """
  candidate: PackingCandidate
  """The courier that would carry the shipment."""
  carrierName: String!
  "ISO 4217 currency code."
  currency: String!
  """The ID of the delivery partner the rate comes from."""
  deliveryPartnerConfigId: String!
  """The earliest expected delivery."""
  etaFrom: DateTime
  """The latest expected delivery."""
  etaTo: DateTime
  """When the price stops being valid."""
  expiresAt: DateTime
  """
  The parcels this price is for (cm / kg) — send them as the booking's parcels to book what was priced. Null when the parcels were given with the request.
  """
  parcels: [DeliveryParcelGql!]
  """The name of the delivery partner."""
  partnerDisplayName: String!
  """The partner's logo, or empty to show a monogram."""
  partnerLogoUrl: String
  """
  The partner's reference for the quote, used when booking at this price.
  """
  providerQuoteRef: String
  """The code of the service level, as the partner names it."""
  serviceLevelCode: String!
  """The name of the service level."""
  serviceLevelName: String!
}

"""The prices delivery partners quoted for a shipment."""
type ShipmentRatesGql {
  """
  The delivery option the customer chose at checkout. Only set for live-quoted orders.
  """
  customerChoice: ShipmentCustomerChoice
  """The prices on offer."""
  options: [ShipmentRateOptionGql!]!
  """
  The order's own shipping charge. Set for an order's outbound rates, empty for a return pickup.
  """
  orderShippingCharge: OrderShippingCharge
  """
  What is left to ship (a return: its items) packed into the tenant's boxes, with box names and contents — pre-fill the parcels from these. With no box enabled it is the default parcel. Null when the request gave its own parcels.
  """
  suggestedParcels: [PackedBox!]
  """The delivery partners that could not give a price, and why."""
  unavailable: [UnavailableDeliveryPartnerGql!]!
}

"""
What to get courier prices for. Give exactly one of an order or a return.
"""
input ShipmentRatesInput {
  """
  Partial shipment: price only these order lines at these ship-now quantities (in each line's unit; each at most what is left to ship). Sales orders only; omitted = everything left to ship.
  """
  lines: [ShipmentRateLineInput!]
  """The ID of the warehouse the shipment leaves."""
  originWarehouseId: String
  """
  The parcels to price. Leave out to pack the goods into the organization's boxes.
  """
  parcels: [DeliveryParcelInput!]
  """
  The ID of a return to quote a pickup for, from the customer's address to the warehouse.
  """
  productReturnId: ID
  "The ID of the sales order."
  salesOrderId: ID
}

"""Who the shipment is delivered to."""
input ShipmentRecipientInput {
  """The recipient's email address."""
  email: String
  """The recipient's name."""
  name: String
  """The recipient's phone number, in international format starting with +."""
  phone: String
}

"""
Where a shipment stands, from DRAFT and booking through pickup and transit to DELIVERED, or a problem such as FAILED_ATTEMPT, EXCEPTION, LOST, CANCELLED or BOOKING_FAILED.
"""
enum ShipmentStatus {
  """Booked and waiting for the courier to collect."""
  AWAITING_PICKUP
  """Booked with the courier."""
  BOOKED
  """The booking is being made."""
  BOOKING
  """The courier refused or failed the booking."""
  BOOKING_FAILED
  """The booking outcome is unknown and needs checking with the courier."""
  BOOKING_ORPHANED
  """Cancelled."""
  CANCELLED
  """Delivered."""
  DELIVERED
  """Being prepared."""
  DRAFT
  """The courier reported a problem."""
  EXCEPTION
  """A delivery attempt failed."""
  FAILED_ATTEMPT
  """On its way."""
  IN_TRANSIT
  """Lost by the courier."""
  LOST
  """Out for delivery."""
  OUT_FOR_DELIVERY
  """Collected by the courier."""
  PICKED_UP
  """Sent back to the seller."""
  RETURNED_TO_SENDER
  """Sent to the courier."""
  SUBMITTED
}

"""
The Shipments list tabs: PENDING (not booked yet), BOOKED (booked / awaiting pickup), IN_TRANSIT (collected or moving), OUT_FOR_DELIVERY, DELIVERED, PROBLEM (failed attempt, exception, lost, returned to sender, booking failed or needing checking), CANCELLED.
"""
enum ShipmentStatusGroup {
  """Booked and not yet collected."""
  BOOKED
  """Cancelled."""
  CANCELLED
  """Delivered."""
  DELIVERED
  """On its way."""
  IN_TRANSIT
  """Out for delivery."""
  OUT_FOR_DELIVERY
  """Not yet booked."""
  PENDING
  """Needs attention."""
  PROBLEM
}

"""How many shipments one list tab holds under a filter."""
type ShipmentStatusGroupCount {
  """How many shipments it holds."""
  count: Int!
  """The list tab."""
  statusGroup: ShipmentStatusGroup!
}

"""
Shipping sticker page layout: one 100×150 mm sticker per page, four per A4 sheet, or the tenant's custom size.
"""
enum ShipmentStickerFormat {
  """Four labels on an A4 sheet."""
  A4_4UP
  """A custom label size."""
  CUSTOM
  """One 4 by 6 inch thermal label."""
  THERMAL_4X6
}

"""
Staff tracking view of a shipment: the shipment, its progress steps, any problem it is in, and the last time the carrier was asked for news (with the carrier's exact error when that ask failed).
"""
type ShipmentTracking {
  """
  True when the carrier can be asked for news: it reports tracking on request, knows this shipment, and the shipment is not finished. False for custom (manual) couriers.
  """
  canAskCarrier: Boolean!
  """
  The carrier's exact error from the last ask, or null. The saved timeline is still returned.
  """
  carrierError: String
  """
  When the carrier was last asked for news (null when it has not been, or cannot be).
  """
  checkedAt: DateTime
  """
  Set while the shipment is in trouble (failed attempt, exception, returned, lost, cancelled, or a booking problem); the stepper keeps the last reached step CURRENT.
  """
  problemStatus: ShipmentStatus
  """
  BOOKED, PICKED_UP, IN_TRANSIT, OUT_FOR_DELIVERY, DELIVERED — in that order.
  """
  progress: [ShipmentProgressStep!]!
  """The shipment."""
  shipment: ShipmentGql!
}

"""The summary strip of the shipments page."""
type ShipmentsSummary {
  """How many pickups are booked and still due."""
  awaitingPickupCount: Int!
  """The courier money per currency. Only set for staff who may ship."""
  money: [ShipmentsSummaryMoney!]
  """How many pickups the courier missed."""
  pickupMissedCount: Int!
  """How many shipments each list tab holds under the filter."""
  statusGroups: [ShipmentStatusGroupCount!]!
  """How many shipments match the filter, every status."""
  total: Int!
  """
  How many shipments have a courier not yet paid. Only set for staff who may ship.
  """
  unpaidCount: Int
}

"""
Narrows the shipments summary. It is the list's filter without paging, status tab or courier payment filter.
"""
input ShipmentsSummaryFilterInput {
  """Only shipments created on or after this moment."""
  dateFrom: DateTime
  """Only shipments created on or before this moment."""
  dateTo: DateTime
  """
  OUTBOUND for order deliveries, RETURN for return pickups. Leave out for both.
  """
  direction: ShipmentDirection
  "Text to search for."
  search: String
}

"""
One currency's courier money on the shipments summary. Amounts are decimal strings, and currencies are never added together.
"""
type ShipmentsSummaryMoney {
  """What the couriers charged."""
  courierCharges: String!
  "ISO 4217 currency code."
  currency: String!
  """What the customers paid towards those charges."""
  customerPaid: String!
  """How many shipments are still owed to the courier."""
  owedCount: Int!
  """Courier charges not yet marked paid."""
  owedToCouriers: String!
  """How many shipments the courier has been paid for."""
  paidCount: Int!
  """Courier charges marked paid."""
  paidToCouriers: String!
  """
  What the customers paid as a percent of the courier charges, to one decimal. Empty when the charges are zero.
  """
  recoveryPercent: Float
  """
  What the seller absorbed: courier charges minus what the customers paid.
  """
  sellerPaid: String!
  """How many shipments with a recorded cost split are in this currency."""
  shipmentCount: Int!
}

"""A home section showing brands to shop by."""
type ShopByBrandsSection {
  """The brands."""
  brands: [HomeBrandCell!]!
  """The kind of home section."""
  kind: HomeSectionKind!
  """The title of the section."""
  title: String
}

"""A home section showing categories to shop by."""
type ShopByCategoriesSection {
  """The categories."""
  categories: [HomeCategoryCell!]!
  """The kind of home section."""
  kind: HomeSectionKind!
  """The title of the section."""
  title: String
}

"""
Input to close a sales order short, giving up the quantity that was never shipped.
"""
input ShortCloseSalesOrderInput {
  """
  The version of the order you last read. The change is refused if someone else changed it since.
  """
  expectedVersion: Int
  """Close only these lines' remaining quantity. Omitted means every line."""
  itemIds: [ID!]
  """
  Why the balance will never be delivered. It is recorded on the order and audited.
  """
  reason: String!
}

"""How a short link was used."""
type ShortUrlAnalytics {
  """Clicks by browser."""
  clicksByBrowser: [ClickByBrowser!]!
  """Clicks by country."""
  clicksByCountry: [ClickByCountry!]!
  """Clicks by day."""
  clicksByDate: [ClickByDate!]!
  """Clicks by kind of device."""
  clicksByDevice: [ClickByDevice!]!
  """How many clicks there were."""
  totalClicks: Int!
  """How many different visitors clicked."""
  uniqueClicks: Int!
}

"""A short link."""
type ShortUrlEntity {
  """How many times the link was clicked."""
  clickCount: Int!
  "When the record was created."
  createdAt: DateTime!
  """The ID of the user who created the link."""
  createdBy: String
  """The custom short code, if one was chosen."""
  customAlias: String
  """What the link is for."""
  description: String
  """When the link stops working."""
  expiresAt: DateTime
  "The unique ID of this record."
  id: String!
  "Whether the record is active."
  isActive: Boolean!
  """When the link was last clicked."""
  lastClickedAt: DateTime
  "Additional data attached to the record, as JSON."
  metadata: JSON
  "The ID of the organization the record belongs to."
  organizationId: String
  """The address the short link leads to."""
  originalUrl: String!
  """The short code."""
  shortCode: String!
  """The full short address."""
  shortUrl: String!
  """Tags on the link."""
  tags: [String!]!
  """A title for the link."""
  title: String
  "When the record was last changed."
  updatedAt: DateTime!
}

"""Stock lost to negative adjustments."""
type ShrinkageSummary {
  """How many negative adjustments there were."""
  adjustmentCount: Int!
  """The quantity lost."""
  quantity: Float!
  """The most common reasons."""
  topReasons: [ReasonSlice!]!
  """The cost value lost."""
  value: Float!
}

"""How to sort a list."""
input SortInput {
  """The field to sort by."""
  field: String!
  """The sort direction. Defaults to ascending."""
  order: SortOrder! = ASC
}

"""Sort order direction"""
enum SortOrder {
  """Smallest or earliest first."""
  ASC
  """Largest or latest first."""
  DESC
}

"""
Why a staff draft has no live delivery price (code DELIVERY_FREIGHT_QUOTE): what it packed to and the store's freight limits.
"""
type StaffDeliveryFreightQuote {
  """How many boxes it packed into."""
  boxCount: Int!
  """The store's freight-quote limit (kg); null when off."""
  freightQuoteAboveKg: Float
  """The store's max boxes per order; null when off."""
  maxBoxesPerOrder: Int
  """The packed weight checked against the limit (kg, boxes included)."""
  packedWeightKg: Float!
}

"""
One live delivery option for a staff draft order. Pass `id` as the order's delivery option; the server re-validates it and charges the quoted fee, never a client figure.
"""
type StaffDeliveryOption {
  """True when the option was picked by the automatic rule."""
  autoSelected: Boolean!
  """
  How many boxes this price is for, when the order was packed into the store's boxes; null for the default parcel.
  """
  boxCount: Int
  """Null when reps see the customer view and courier names are hidden."""
  carrierName: String
  """ISO-4217 currency of `fee`."""
  currency: String!
  """The ID of the delivery partner the option comes from."""
  deliveryPartnerConfigId: ID!
  """The latest expected delivery."""
  estimatedDelivery: DateTime
  """The earliest expected delivery."""
  estimatedDeliveryFrom: DateTime
  """When the price stops being valid."""
  expiresAt: DateTime!
  """
  The order's shipping charge when picked: the carrier's quoted price as-is (no threshold, no tax on top), in `currency`.
  """
  fee: Float!
  """The carrier's price before tax when it breaks it out, else null."""
  feeExclTax: Float
  """Opaque option id (expires at `expiresAt`)."""
  id: ID!
  """
  SERVICE, SPEED or AUTO — only other than SERVICE when the store shows reps the customer view.
  """
  kind: DeliveryOptionKind!
  """
  The row title: speed name (SPEED), "Delivery" (AUTO / all hidden — translate by `kind`), else "courier · service".
  """
  label: String!
  """Null when reps see the customer view and courier names are hidden."""
  partnerDisplayName: String
  """The partner's logo (an image URL or PNG data URI), or null."""
  partnerLogoUrl: String
  """
  Null when reps see the customer view and the courier or service name is hidden.
  """
  serviceLevelCode: String
  """Null when reps see the customer view and service names are hidden."""
  serviceLevelName: String
  """The ID of the delivery speed the option stands for, in SPEEDS mode."""
  speedId: String
}

"""
Live delivery options for a staff draft order. `available` false: the plan has no delivery partners or none is enabled — keep the manual shipping amount.
"""
type StaffDeliveryOptions {
  """True when delivery options could be worked out."""
  available: Boolean!
  """
  LIST unless the store shows reps the customer view (then the customer choice mode).
  """
  choiceMode: DeliveryChoiceMode!
  """
  DELIVERY_PARTNERS_NOT_IN_PLAN, NO_ENABLED_PARTNERS, NO_DELIVERY_OPTIONS or DELIVERY_FREIGHT_QUOTE (too heavy to price live — set the shipping charge by hand); null when options exist.
  """
  code: String
  """Set with code DELIVERY_FREIGHT_QUOTE; null otherwise."""
  freightQuote: StaffDeliveryFreightQuote
  """The delivery options on offer."""
  options: [StaffDeliveryOption!]!
  """True when asking again may succeed."""
  retryable: Boolean!
  """The delivery partners that could not give an option, and why."""
  unavailable: [CheckoutDeliveryUnavailable!]!
}

"""The draft order to get delivery options for."""
input StaffDeliveryOptionsInput {
  """The order currency; the org base currency when omitted."""
  currency: String
  "The ID of the customer."
  customerId: ID!
  """The lines of the draft order."""
  lines: [StaffDeliveryOptionsLineInput!]!
  """The customer's address the order ships to."""
  shippingAddressId: ID!
  """
  The warehouse the order would ship from, used when Settings → Shipment has no Default pickup warehouse.
  """
  warehouseId: ID
}

"""One line of the draft order."""
input StaffDeliveryOptionsLineInput {
  """The quantity on the line."""
  quantity: Float!
  """
  The line's unit of measure — send exactly what the order will carry (part of the option's binding).
  """
  uomId: ID
  "The ID of the product variant."
  variantId: ID!
  """
  The warehouse picked on the line. The courier is quoted from the warehouse holding most of the quantity, else the input's warehouseId.
  """
  warehouseId: ID
}

"""Starts reading an uploaded file."""
input StartCopilotParseInput {
  """The key of the uploaded file."""
  fileKey: String!
  """The ID of the conversation."""
  sessionId: ID!
}

"""Starts finding images for variants."""
input StartImageSourcingInput {
  """The ID of the conversation."""
  sessionId: ID!
  """The IDs of the variants."""
  variantIds: [ID!]
}

"""Starts an AI edit of the storefront theme."""
input StartStorefrontEditInput {
  """
  The selected block's id, when a block of the selected section is selected.
  """
  blockId: String
  """The preview the seller is looking at: 'desktop' or 'mobile'."""
  device: String
  """
  The editor's draft as it is on screen (a StorefrontDraft document from @arc/theme-engine), checked like a save. Read to build what the model sees; never stored.
  """
  draft: JSON!
  """
  Write with Minori in one text field: the id of a text, textarea or richtext field of the selected section (or of its selected block). Only that field may change; any other edit the model writes is skipped with the reason. Needs sectionId.
  """
  fieldId: String
  """
  The id of the page on screen. Its sections, with the shared header and footer, are what the edits may change.
  """
  pageId: String!
  """
  The seller's own sentence asking for a change to the page's values (copy, options, style, visibility, order, names, theme).
  """
  request: String!
  """The selected section's id, when one is selected."""
  sectionId: String
}

"""Starts AI generation of a storefront page."""
input StartStorefrontPageInput {
  """
  The sections already on the page, top to bottom, as 'handle@version' (e.g. 'slideshow@2'). No values or copy.
  """
  currentPage: [String!]
  """
  Up to 3 reference images (a screenshot of a page to match). They reach the model on the first turn only and are never stored.
  """
  images: [StorefrontSectionImageInput!]
  """'home' or 'page'."""
  pageType: String
  """
  Where on the page the sections go, in words (e.g. 'below Hero'): the seller's selection, or the end of the page. The editor places them there itself.
  """
  placement: String
  """
  The seller's own sentence describing the page (or part of a page) they want.
  """
  request: String!
}

"""Starts AI generation of a storefront section."""
input StartStorefrontSectionInput {
  """
  Up to 3 images the seller attached: a screenshot or sketch of a layout, or photos. They reach the model on the first turn only and are never stored.
  """
  images: [StorefrontSectionImageInput!]
  """'home' or 'page'."""
  pageType: String
  """Where on the page the section goes, e.g. 'below Hero'."""
  placement: String
  """
  Ask for a corrected version of a previously generated section, with the errors found in it.
  """
  repair: StorefrontSectionRepairInput
  """
  The seller's own sentence describing the section they want. With `revise`, the change they want made to it.
  """
  request: String!
  """
  Change an existing section as `request` asks (a follow-up instruction). The model keeps its setting ids, block types and field types where it can, so the values the seller already typed still apply, and returns the whole section. Not together with `repair`.
  """
  revise: StorefrontSectionReviseInput
}

"""A state or region to pick from."""
type StateListItem {
  """The capital of the state."""
  capital: String
  """The state code."""
  code: String!
  """The name of the state."""
  name: String!
}

"""A movement of stock: a receipt, issue, transfer or adjustment."""
type StockMovement {
  """
  Current AVAILABLE stock (on hand minus reserved) for this item at the movement's affected warehouse. Warehouse-scoped, summed across bins/batches/serials, reflects NOW.
  """
  availableQuantity: Float
  """
  Stock on hand at the movement's affected warehouse immediately AFTER this movement — a running ledger balance (anchored to current stock, walked back through newer movements). Null when the movement has no resolvable warehouse.
  """
  balanceQuantity: Float
  """The batch number of the stock."""
  batchNumber: String
  """The cost of one unit the stock moved at."""
  cost: Float!
  """
  Costing method in force when this movement was costed (FIFO | LIFO | AVERAGE). Recorded per-movement so changing the org setting cannot restate history.
  """
  costingMethod: String
  "When the record was created."
  createdAt: DateTime!
  """The warehouse the stock leaves."""
  fromWarehouse: Warehouse
  "The unique ID of this record."
  id: ID!
  """The movement number, unique within the organization."""
  movementNumber: String!
  """Notes about the movement."""
  notes: String
  """
  Current stock on hand for this item at the movement's affected warehouse. Warehouse-scoped and summed across bins/batches/serials — reflects the level NOW, not the balance at the time of the movement.
  """
  onHandQuantity: Float
  """When the movement was done."""
  performedAt: DateTime
  """The ID of the user who did the movement."""
  performedBy: String!
  """The user who did the movement."""
  performedByUser: User!
  """The product moved."""
  product: Product!
  """The quantity moved."""
  quantity: Float!
  """Stock on hand for this line immediately after the movement."""
  quantityAfter: Float
  """Stock on hand for this line immediately before the movement."""
  quantityBefore: Float
  """Why the movement was made."""
  reason: String
  """The ID of that document."""
  referenceId: ID
  """
  The kind of document that caused the movement, for example a sales order.
  """
  referenceType: String
  """
  Current RESERVED stock (committed to open orders) for this item at the movement's affected warehouse. Warehouse-scoped, summed across bins/batches/serials, reflects NOW. Reservations are not stock movements — this is why on-hand and available differ.
  """
  reservedQuantity: Float
  """The serial number of the stock."""
  serialNumber: String
  """The status of the movement."""
  status: MovementStatus!
  """The warehouse the stock goes to."""
  toWarehouse: Warehouse
  """The cost of the whole movement."""
  totalCost: Float!
  """The kind of movement."""
  type: MovementType!
  """
  Unit cost the line carries after the movement. On a cost adjustment this is the entered New Cost.
  """
  unitCostAfter: Float
  """Unit cost the line carried before the movement."""
  unitCostBefore: Float
  """The unit of measure of the quantity."""
  uom: UnitOfMeasure!
  "When the record was last changed."
  updatedAt: DateTime!
  """
  Signed change in the line's total value. For an outbound movement this is the negated COGS the cost layers actually gave up — under FIFO/LIFO that is NOT quantity × average cost.
  """
  valueChange: Float
  """The variant moved."""
  variant: ProductVariant
}

"""Filters for the stock movement list."""
input StockMovementFilterInput {
  """Only movements of this batch."""
  batchNumber: String
  """Only movements created on or after this date."""
  createdAtFrom: String
  """Only movements created on or before this date."""
  createdAtTo: String
  """Only movements done on or after this date."""
  performedAtFrom: String
  """Only movements done on or before this date."""
  performedAtTo: String
  "The ID of the product."
  productId: ID
  """Only movements caused by this document."""
  referenceId: ID
  """Only movements caused by this kind of document."""
  referenceType: String
  "Text to search for."
  search: String
  """Only movements of this serial number."""
  serialNumber: String
  """Only movements in this status."""
  status: MovementStatus
  """Only movements of this kind."""
  type: MovementType
  "The ID of the product variant."
  variantId: ID
  "The ID of the warehouse."
  warehouseId: ID
}

"""How to sort the stock movement list. Give one column."""
input StockMovementOrderByInput {
  """Sort by when the movement was created."""
  createdAt: SortOrder
  """Sort by movement number."""
  movementNumber: SortOrder
  """Sort by when the movement was done."""
  performedAt: SortOrder
  """Sort by quantity."""
  quantity: SortOrder
}

"""
One block of a section the buyer app draws: its type and its resolved settings.
"""
type StorefrontAppBlock {
  """The block's instance id in the document."""
  id: String!
  """
  The block's values, read against its definition: every field present, a stored value only where it fits the field, else the field's default (the engine's resolveValues). Links are @arc/theme-engine link values.
  """
  settings: JSON!
  """The block type the section declares (a slide, a tile, a logo …)."""
  type: String!
}

"""
A page of the storefront buyers see in the buyer app: the LIVE published theme (never the draft), or the basic default theme when the store has published nothing. Only the page's own sections; the app keeps its own header and tab bar, so the theme's shared header and footer are not included.
"""
type StorefrontAppPage {
  """
  True when the store has published nothing and this is the basic default theme.
  """
  isDefault: Boolean!
  """The live version's number; null for the default theme."""
  liveVersion: Int
  """
  The page or template drawn (its id in the document); null when the document has no page of that kind.
  """
  pageId: String
  """The page's sections shown in the app, top to bottom."""
  sections: [StorefrontAppSection!]!
}

"""Which page of the live storefront theme the buyer app draws"""
enum StorefrontAppPageKind {
  """
  A Category template: the alternate template assigned to the category, else the default Category template.
  """
  CATEGORY
  """The home page: the app's Discover tab."""
  HOME
  """The Search template: its sections around the search results."""
  SEARCH
}

"""
A section of the live storefront page that shows in the buyer app (not hidden, not Web only by the seller's choice). The app draws the ones it can (@arc/theme-engine ARC_APP_SECTIONS) and skips the rest.
"""
type StorefrontAppSection {
  """
  On a store page's template (Search, Category): true when the section sits below the main area (the results or the product grid), false above it. Always false on the home page.
  """
  belowMain: Boolean!
  """The section's blocks buyers see, in order; hidden blocks are left out."""
  blocks: [StorefrontAppBlock!]!
  """The section's handle in the library (slideshow, category-tiles …)."""
  handle: String!
  """The placed section's instance id in the document."""
  id: String!
  """
  The live catalog records the section lists (Picked: in the seller's order; Automatic: catalog order). Null when the section lists no live records (typed by hand), or the catalog does not list that source in that mode.
  """
  records: [StorefrontCatalogRecord!]
  """
  The section's values, read against its definition with defaults applied (the engine's resolveValues).
  """
  settings: JSON!
  """The section definition's version the seller placed."""
  version: Int!
}

"""How a storefront section chooses its catalog records"""
enum StorefrontCatalogMode {
  """
  Categories only: active categories at level 0 or 1, in catalog order (sortOrder, then name).
  """
  AUTO
  """Products only: the newest products of one brand."""
  IN_BRAND
  """
  Products only: the newest products in one category or any category under it.
  """
  IN_CATEGORY
  """Products only: the newest products first."""
  NEWEST
  """
  The records the seller picked, by id, in the seller's order. Any source.
  """
  PICKED
}

"""
One live catalog record for a storefront section. It carries only what the section shows: a name, an image and, for a category, a product count.
"""
type StorefrontCatalogRecord {
  "The unique ID of this record."
  id: ID!
  """
  The record's image: a category image, a brand logo, or a product's picture as buyer surfaces show it (the first variant's photo, else the product's). Our own stored files come back as relative /api/upload/serve/ paths; null when the record has none.
  """
  imageUrl: String
  """The name of the record."""
  name: String!
  """
  Categories only, when the request set withProductCount: how many active products are in the category or any category under it. A product counts once, however many variants or categories it has; it needs at least one active variant. Null otherwise.
  """
  productCount: Int
}

"""The requests of every storefront section in one object."""
input StorefrontCatalogRecordsInput {
  """One entry per section. At most 50."""
  requests: [StorefrontCatalogRequestInput!]!
}

"""
One storefront section's request: which kind of record, and how they are chosen. A combination of mode, source and fields outside the allowed set is refused.
"""
input StorefrontCatalogRequestInput {
  """
  IN_BRAND only, and required there: the brand whose products are listed.
  """
  brandId: ID
  """
  IN_CATEGORY only, and required there: the category whose products, and those of every category under it, are listed.
  """
  categoryId: ID
  """
  PICKED only, and required there: the picked record ids in the seller's order. At most 16.
  """
  ids: [ID!]
  """
  AUTO, NEWEST, IN_CATEGORY and IN_BRAND: how many records, 1 to 16; 16 when left out.
  """
  limit: Int
  """
  How the records are chosen. PICKED when left out. AUTO takes CATEGORIES; NEWEST, IN_CATEGORY and IN_BRAND take PRODUCTS; PICKED takes any source.
  """
  mode: StorefrontCatalogMode
  """
  AUTO only: leave out categories with no active product in them or in any category under them.
  """
  onlyWithProducts: Boolean
  """Which kind of record to read."""
  source: StorefrontCatalogSource!
  """
  CATEGORIES with PICKED or AUTO only: give each record its productCount.
  """
  withProductCount: Boolean
}

"""The records for one storefront section request."""
type StorefrontCatalogResult {
  """
  Active records of this organization. PICKED keeps the order picked and leaves out ids that match no active record (deleted, inactive or another organization's); AUTO keeps catalog order; the product modes list the newest first.
  """
  records: [StorefrontCatalogRecord!]!
}

"""The kind of catalog record a storefront section lists"""
enum StorefrontCatalogSource {
  """Brands."""
  BRANDS
  """Categories."""
  CATEGORIES
  """Products."""
  PRODUCTS
}

"""Where the Home CMS cutover puts a group of sections, and their names."""
type StorefrontCutoverLine {
  """The sections."""
  sections: [String!]!
  """Where the sections are used."""
  where: String!
}

"""
What the Home CMS cutover did, or in a dry run would do, for one organization.
"""
type StorefrontCutoverOrgReport {
  """FAILED: the step and the exact error."""
  error: String
  """Home CMS rows read."""
  homeCmsRows: Int!
  """What did not come in, and why."""
  leftOut: [String!]!
  """The findings for the organization."""
  lines: [StorefrontCutoverLine!]!
  """The name of the organization."""
  name: String!
  """What came in hidden, changed or added."""
  notes: [String!]!
  """How many of them on the home page."""
  onHome: Int!
  "The ID of the organization the record belongs to."
  organizationId: ID!
  """Sections the theme gets from the Home CMS."""
  sections: Int!
  """
  WOULD_PUBLISH (dry run), PUBLISHED, SKIPPED_HAS_THEME (a theme or version exists, nothing touched), NOTHING_TO_IMPORT (no Home CMS rows, nothing written: the default theme shows) or FAILED (see error).
  """
  status: String!
  """The subdomain of the organization."""
  subdomain: String!
  """The ID of the theme version."""
  versionId: ID
  """The number of the theme version."""
  versionNumber: Int
}

"""The Home CMS cutover's report (ruling 5)."""
type StorefrontCutoverReport {
  """True when nothing was written."""
  dryRun: Boolean!
  """The findings for each organization."""
  organizations: [StorefrontCutoverOrgReport!]!
}

"""The result of saving the storefront theme draft."""
type StorefrontDraftSaved {
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A started storefront edit."""
type StorefrontEditJob {
  """
  Platform billing figure in USD — Growmax billing the tenant, not tenant money.
  """
  costDisplay: String
  """The credits used so far, in cents."""
  creditsUsedCents: Int
  """The upstream failure, verbatim. Never a generic fallback."""
  error: String
  """The ID of the job."""
  jobId: ID!
  """
  While the job runs: the tail of any prose the model writes outside its edits (usually empty). Empty once the job ends.
  """
  partial: String
  """
  On COMPLETED: { pageId, edits, skipped, summary?, unmet?, answer? }. `edits` are checked value edits in ids, in order ({ from, why, kind: setValue|setStyle|setHidden|setSurfaces|move|setLabel|setTheme, … }), for the editor to apply as one undo step after checking each again (@arc/theme-engine checkEdit). `skipped` lists each requested edit that could not be used ({ index, op, why, reason, sectionId?, blockId?, field?, value? }). `answer` is the reply in plain text when the seller asked a question (help mode), usually with no edits. Writes nothing.
  """
  result: JSON
  """
  What the job is doing now: queued, reading, editing, repairing, checking, done, failed or cancelled. A plain string, so treat a value you do not know as 'editing'.
  """
  stage: String!
  """
  The same lifecycle as a section job (StorefrontSectionJobStatus is registered once, for all storefront jobs).
  """
  status: StorefrontSectionJobStatus!
}

"""
The other open editors of this storefront, and when its draft was last saved.
"""
type StorefrontEditorHeartbeat {
  """
  The stored draft's updatedAt (its version stamp); null when nothing has been saved. An editor whose own stamp is older knows someone else saved.
  """
  draftUpdatedAt: DateTime
  """
  The other editors that checked in during the last 90 seconds, most recent first; this window is not listed. Empty when presence is unavailable.
  """
  editors: [StorefrontEditorPresence!]!
}

"""
What one open storefront editor reports about itself: which window it is, whether it has unsaved changes, and the page it shows.
"""
input StorefrontEditorHeartbeatInput {
  """Whether this editor has changes it has not saved yet."""
  dirty: Boolean!
  """
  The id of the page or template this editor shows, as the draft names it. Shown to the others; null when none is open yet.
  """
  pageId: String
  """
  This editor window's own id, made by the editor when it opens (8–64 letters, digits, - or _). A second window of the same person has its own.
  """
  sessionId: String!
}

"""
Another open editor of this organization's storefront: who, whether they have unsaved changes, and the page they show.
"""
type StorefrontEditorPresence {
  """Whether that editor has changes it has not saved yet."""
  dirty: Boolean!
  """When that editor last checked in."""
  lastSeenAt: DateTime!
  """
  The person's name as the organization's user record has it, resolved by the server; null when the record has none.
  """
  name: String
  """
  The id of the page or template that editor shows; null when it reported none.
  """
  pageId: String
  """
  True when it is the signed-in person themself, in another window or tab.
  """
  self: Boolean!
  """
  That editor window's own id (its heartbeat's sessionId). Stable while the window stays open.
  """
  sessionId: String!
}

"""
A picture this organization uploaded for its storefront (the theme editor's image fields).
"""
type StorefrontImage {
  """The file's size in bytes."""
  size: Int!
  """When it was uploaded."""
  uploadedAt: DateTime!
  """
  The stored file's relative serve path (`/api/upload/serve/<key>`), the value an image field stores.
  """
  url: String!
}

"""One page of the storefront's picture library, newest first."""
type StorefrontImagePage {
  """Whether a later page has more."""
  hasMore: Boolean!
  """This page's pictures, newest first."""
  images: [StorefrontImage!]!
  """The page size used."""
  limit: Int!
  """This page's number, from 1."""
  page: Int!
  """How many pictures the library holds in all."""
  total: Int!
}

"""A started storefront page generation."""
type StorefrontPageJob {
  """
  Platform billing figure in USD — Growmax billing the tenant, not tenant money.
  """
  costDisplay: String
  """The credits used so far, in cents."""
  creditsUsedCents: Int
  """The upstream failure, verbatim. Never a generic fallback."""
  error: String
  """The ID of the job."""
  jobId: ID!
  """
  On COMPLETED: { import, sections, unmet, journeys }. `import` is an importer's answer for the theme editor ({ placements, leftOut, notes }: built-in library sections only, on the home page; the editor places them where the seller asked). `sections` describes each imported section in order: { index, kind, name, why?, surfaces, twinOf?, appDraws, needsPicture, records: [{ type, id, name }], journeys: [{ id, label, via }], placeholders }. `unmet` lists what the library cannot show ({ what, journey }), and `journeys.used` the journeys the page opens. Writes nothing.
  """
  page: JSON
  """
  While the job runs: the tail of any prose the model writes outside its plan (usually empty). Empty once the job ends.
  """
  partial: String
  """
  What the job is doing now: queued, reading, choosing, repairing, filling, done, failed or cancelled. A plain string, so treat a value you do not know as 'choosing'.
  """
  stage: String!
  """
  The same lifecycle as a section job (StorefrontSectionJobStatus is registered once, for both).
  """
  status: StorefrontSectionJobStatus!
}

"""Which page of the published storefront a host asks for"""
enum StorefrontPageKind {
  """
  The template a brand uses: the alternate it is assigned to, else the default.
  """
  BRAND
  """
  The template a category uses: the alternate it is assigned to, else the default.
  """
  CATEGORY
  """The shared header and footer only, for the store's own pages."""
  CHROME
  """A custom page, by its slug (/pages/<slug>)."""
  CUSTOM
  """The home page."""
  HOME
  """
  The template a product uses: the alternate it is assigned to, else the default.
  """
  PRODUCT
  """The Search template."""
  SEARCH
}

"""Where a storefront request was routed."""
type StorefrontRequestRoute {
  """Jev's probability for its choice, when it was asked."""
  confidence: Float
  """
  Platform billing figure in USD — Growmax billing the tenant, not tenant money.
  """
  costDisplay: String!
  """The credits used, in cents."""
  creditsUsedCents: Int!
  """
  Who decided: 'jev' (the typed decider) or 'model' (the fallback model).
  """
  decidedBy: String!
  """
  'page': the page composer plans several library sections; 'section': the section writer writes one. A plain string, so treat a value you do not know as 'section'.
  """
  scope: String!
}

"""
An image the seller attached to a request. It is checked for size and type and sent to the model with the first message only.
"""
input StorefrontSectionImageInput {
  """
  The image bytes, base64-encoded, with no data: prefix. At most 5 MB once decoded.
  """
  data: String!
  """'image/png', 'image/jpeg' or 'image/webp'."""
  mimeType: String!
  """
  The file's name, for the client's own bookkeeping. Never sent to the model.
  """
  name: String
}

"""A storefront section generation."""
type StorefrontSectionJob {
  """
  Platform billing figure in USD — Growmax billing the tenant, not tenant money.
  """
  costDisplay: String
  """The credits used so far, in cents."""
  creditsUsedCents: Int
  """
  The upstream failure, verbatim. Never a generic fallback. A job whose server stopped before it finished (a deploy, a crash) reads FAILED with a message that says so.
  """
  error: String
  """The ID of the job."""
  jobId: ID!
  """
  While the job runs: the last ~3000 characters of PROSE the model has written outside the section, refreshed at most every ~700 ms. The section itself is in `writing` as it is written, and the model is told to answer only with the section, so this is usually empty or one short sentence: drive a live placeholder from `stage` (and `writing`), and show this only when present. Never validated, never a section. Empty once the job ends.
  """
  partial: String
  """
  On COMPLETED: { handle, name, description, category?, version, source: 'ai', liquid, css, settings, blocks?, maxBlocks?, presetBlocks?, brief, revisedFrom? }. A fresh section has a new handle and version 1. A revision of an AI section keeps its handle with version + 1; a revision of any other section gets a new handle. `revisedFrom` names the { handle, version } that was revised. A repair (`repair`) keeps the repaired section's identity: its AI handle and version as they were, and its revisedFrom.
  """
  section: JSON
  """
  What the job is doing now: queued, writing, checking, repairing, done, failed or cancelled. A plain string, so treat a value you do not know as 'writing'.
  """
  stage: String!
  """Where the job stands."""
  status: StorefrontSectionJobStatus!
  """
  On COMPLETED: the parts of the request the section does NOT build, in the seller's terms, as the model reported them (the other sections a page request names, records of a second source, anything a section cannot do). Empty when it covers the whole request. Show it with the section, so a seller never reads a part as built that was not. Not part of the section definition.
  """
  unmet: [String!]
  """
  While the model writes the section: which part it is on and that part's tail, refreshed at most every ~700 ms. Null before it starts writing the section, while it checks, and once the job ends. Unchecked: show as plain text only.
  """
  writing: StorefrontSectionWriting
}

"""
Where a storefront section generation stands: PENDING, RUNNING, COMPLETED, FAILED or CANCELLED.
"""
enum StorefrontSectionJobStatus {
  """Cancelled."""
  CANCELLED
  """Finished."""
  COMPLETED
  """Stopped with an error."""
  FAILED
  """Queued and not started."""
  PENDING
  """In progress."""
  RUNNING
}

"""Asks the AI to repair a storefront section."""
input StorefrontSectionRepairInput {
  """The validation errors the client's engine found, verbatim."""
  errors: [String!]!
  """
  The previously generated section (as returned in StorefrontSectionJob.section) that the client's engine refused. Send it whole, with its handle, version, source and revisedFrom: the repaired section keeps that identity.
  """
  section: JSON!
}

"""Asks the AI to revise a storefront section."""
input StorefrontSectionReviseInput {
  """
  The section definition the editor holds now: the model's own earlier output or a built-in's code ({ handle, version, name, description, category, liquid, css, settings, blocks, maxBlocks, presetBlocks }). Only its CODE reaches the model; the server drops any field values or placed-section data sent with it.
  """
  section: JSON!
}

"""
What the section writer is writing now, read from the model's tool input as it streams. A preview: unchecked until the section is finished, so show it as plain text only.
"""
type StorefrontSectionWriting {
  """
  The last ~480 characters of that part as written so far (a text field decoded, a list as its JSON). Unchecked: plain text, never markup to render.
  """
  codeTail: String!
  """
  The part of the section being written, by its field: brief, name, description, category, liquid (the layout), css (the styles), settings (the fields), blocks, maxBlocks, presetBlocks or data. A client shows a key it does not know as writing the section.
  """
  key: String!
  """The section's name, once the model has written it whole; null before."""
  name: String
}

"""
The organization's storefront theme: its saved draft and the version buyers see.
"""
type StorefrontThemeState {
  """
  The editor's saved draft (a StorefrontDraft document from @arc/theme-engine). Null when nothing has been saved yet.
  """
  draft: JSON
  """
  The `updatedAt` inside the live version's document. When it equals the draft's own `updatedAt`, the draft on screen is exactly what buyers see. Null until the first publish.
  """
  liveDraftUpdatedAt: String
  """The version buyers see. Null until the first publish."""
  liveVersion: StorefrontThemeVersionSummary
  """When the draft was last saved."""
  updatedAt: DateTime
}

"""
A published version of the storefront theme. Immutable: rolling back points the store at an older one.
"""
type StorefrontThemeVersionSummary {
  "The unique ID of this record."
  id: ID!
  """1, 2, 3 … in publish order."""
  number: Int!
  """When the version was published."""
  publishedAt: DateTime!
  """
  Who published it, by name; null when that user no longer exists in this organization.
  """
  publishedByName: String
}

"""A filter on text."""
input StringFilter {
  """True to ignore upper and lower case. Defaults to true."""
  caseInsensitive: Boolean = true
  """How to compare. Defaults to contains."""
  operator: FilterOperator = CONTAINS
  """The text to compare with."""
  value: String
  """Several texts to compare with."""
  values: [String!]
}

type Subscription {
  """
  Sends each new chat message as it arrives, to the people who may see its conversation.
  """
  messageAdded: ChatMessage!
  """
  Status updates for a single order. v1 carries status + message; emitted on PLACED, CONFIRMED, OUT_FOR_DELIVERY, DELIVERED, CANCELLED.
  """
  orderUpdates(
    """The ID of the order."""
    orderId: ID!
  ): MobileOrderUpdate!
}

"""
A product suggested for upsell or cross-sell. It carries just enough for a card.
"""
type SuggestedProduct {
  "The unique ID of this record."
  id: ID!
  """The URL of the product image."""
  imageUrl: String
  """The name of the product."""
  name: String!
}

"""How one supplier performed."""
type SupplierPerf {
  """The average days from order to delivery."""
  avgLeadTimeDays: Float!
  """The quantity received as a percent of the quantity ordered."""
  fillRatePct: Float!
  """The name of the supplier."""
  name: String!
  """The share of deliveries that arrived on time, in percent."""
  onTimePct: Float!
  """How many purchase orders were raised."""
  poCount: Int!
  """The quantity rejected as a percent of the quantity received."""
  rejectionRatePct: Float!
  "The ID of the supplier."
  supplierId: ID!
}

"""The delivery figures a supplier rating was worked out from."""
type SupplierRatingMetrics {
  """How many issues were reported."""
  issuesReported: Int!
  """How many deliveries arrived on time."""
  onTimeDeliveries: Int!
  """How many deliveries there were."""
  totalDeliveries: Int!
  """How many goods receipts there were."""
  totalGRNs: Int!
}

"""The result of working out a supplier's rating."""
type SupplierRatingResult {
  """The delivery rating."""
  deliveryRating: Float
  """A message about the outcome."""
  message: String!
  """The figures the rating was worked out from."""
  metricsUsed: SupplierRatingMetrics
  """The overall rating."""
  overallRating: Float
  """The performance rating."""
  performanceRating: Float
  """The quality rating."""
  qualityRating: Float
  """The service rating."""
  serviceRating: Float
  """True when the rating was worked out."""
  success: Boolean!
  "The ID of the supplier."
  supplierId: String
}

"""A saved way of reading one supplier's price list."""
type SupplierRuleType {
  """Which column of the file feeds each product field."""
  columnMap: JSON
  """How to work out the minimum order quantity."""
  moqRule: String
  """How to work out the price."""
  priceRule: String
  """When the rule was saved."""
  savedAt: String!
  """Who saved it."""
  savedBy: String!
  """The name of the supplier."""
  supplierName: String!
}

"""How suppliers performed."""
type SupplierScorecard {
  """The suppliers."""
  suppliers: [SupplierPerf!]!
}

"""Switches the user to another organization they belong to."""
input SwitchOrganizationInput {
  """The ID of the organization."""
  organizationId: String!
}

"""The result of a system action."""
type SystemActionResponse {
  """A message about the outcome."""
  message: String!
  """True when the action succeeded."""
  success: Boolean!
}

"""The health of the system."""
type SystemHealth {
  """The share of requests that failed, in percent."""
  errorRate: Float!
  """The average response time, in milliseconds."""
  responseTime: Float!
  """The share of time the system was up, in percent."""
  uptime: Float!
}

"""System settings."""
input SystemSettingsInput {
  """True to switch debug mode on."""
  debugMode: Boolean
  """The default theme."""
  defaultTheme: String
  """True to collect analytics."""
  enableAnalytics: Boolean
  """How much is logged."""
  logLevel: String
  """The message shown during maintenance."""
  maintenanceMessage: String
  """True to put the system in maintenance mode."""
  maintenanceMode: Boolean
  """The name of the system."""
  systemName: String
  """The version of the system."""
  systemVersion: String
}

"""The tax worked out on an amount."""
type TaxCalculation {
  """The amount the tax was worked out on."""
  baseAmount: Float!
  """The amount including tax."""
  finalAmount: Float!
  """The tax of each rate."""
  taxBreakdown: [TaxLineItem!]!
  """The total tax."""
  totalTaxAmount: Float!
}

"""An amount to work tax out on."""
input TaxCalculationInput {
  """The amount before tax."""
  baseAmount: Float!
  """The city of the sale."""
  city: String
  """The country of the sale."""
  country: String
  "ISO 4217 currency code."
  currency: String
  """The postal code of the sale."""
  postalCode: String
  """The product categories of the sale."""
  productCategories: [String!]
  """The state or region of the sale."""
  state: String
  "The ID of the tax group."
  taxGroupId: String
  """The IDs of the tax rates to apply."""
  taxRateIds: [String!]
}

"""
How a tax is worked out against the price: INCLUSIVE when the price already holds it, EXCLUSIVE when it is added on, COMPOUND when it is charged on top of other tax, ADDITIVE when several taxes are added together.
"""
enum TaxCalculationMethod {
  """Added on top of the price, alongside other taxes."""
  ADDITIVE
  """Calculated on the price plus earlier taxes."""
  COMPOUND
  """Added on top of the price."""
  EXCLUSIVE
  """Already included in the price."""
  INCLUSIVE
}

"""A set of tax rates applied together."""
type TaxGroup {
  """How the rates in the group combine."""
  calculationMethod: String!
  """The code of the group."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  """What the group is for."""
  description: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The name of the group."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The tax rates in the group."""
  taxRates: [TaxGroupRate!]
  "When the record was last changed."
  updatedAt: DateTime!
}

"""The outcome of a tax group import."""
type TaxGroupBulkImportResult {
  """The rejected rows, and why."""
  errors: [TaxGroupImportError!]!
  """How many rows were rejected."""
  failed: Int!
  """How many rows were imported."""
  success: Int!
}

"""Sorting for the tax group list."""
input TaxGroupFiltersInput {
  "Whether the record is active."
  isActive: Boolean
  "Text to search for."
  search: String
  """The column to sort by. Defaults to name, A to Z."""
  sortBy: TaxGroupSortField
  """The sort direction."""
  sortOrder: SortOrder
}

"""A tax group import row that was rejected."""
type TaxGroupImportError {
  """What was wrong with the row."""
  errors: [String!]!
  """The row number in the file."""
  row: Int!
  """The name of the tax group on the row."""
  taxGroupName: String!
}

"""A tax rate in a tax group."""
type TaxGroupRate {
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  "The ID of the tax group."
  taxGroupId: String!
  """The tax rate."""
  taxRate: TaxRate
  """The ID of the tax rate."""
  taxRateId: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A column the tax group list can be sorted by."""
enum TaxGroupSortField {
  """The group code."""
  CODE
  """When the group was created."""
  CREATED_AT
  """The group name."""
  NAME
}

"""Totals for the tax group list, over the whole set."""
type TaxGroupSummary {
  """How many are active."""
  activeTaxGroups: Int!
  """
  The mean of each group's combined rate in percent. 0 when there are no groups.
  """
  averageGroupRate: Float!
  """How many groups were updated in the last seven days."""
  recentlyUpdated: Int!
  """How many rate assignments there are across live groups."""
  totalAssignedRates: Int!
  """How many tax groups there are."""
  totalTaxGroups: Int!
}

"""
The level a tax applies at: FEDERAL, STATE, COUNTY, CITY or CUSTOM zone.
"""
enum TaxJurisdiction {
  """A city."""
  CITY
  """A county."""
  COUNTY
  """A jurisdiction you define."""
  CUSTOM
  """A national government."""
  FEDERAL
  """A state or province."""
  STATE
}

"""The tax of one rate on an amount."""
type TaxLineItem {
  """How the tax was worked out."""
  calculationMethod: TaxCalculationMethod!
  """The rate, in percent."""
  rate: Float!
  """The tax."""
  taxAmount: Float!
  """The code of the tax rate."""
  taxCode: String!
  """The name of the tax rate."""
  taxName: String!
  """The ID of the tax rate."""
  taxRateId: String!
  """The kind of tax."""
  taxType: TaxType!
  """The amount the tax was worked out on."""
  taxableAmount: Float!
}

"""A tax rate."""
type TaxRate {
  """How the tax is worked out against the price."""
  calculationMethod: String
  """The city the tax applies in."""
  city: String
  """The code of the tax rate."""
  code: String!
  """The country the tax applies in."""
  country: String!
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  """What the tax rate is for."""
  description: String
  """ID of the tax group this rate belongs to"""
  groupId: String
  """Name of the tax group this rate belongs to"""
  groupName: String
  """Tax group type: INTRASTATE, INTERSTATE, or UNKNOWN"""
  groupType: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """The level the tax applies at."""
  jurisdiction: String!
  """The largest amount the tax applies to."""
  maximumAmount: Float
  """The smallest amount the tax applies to."""
  minimumAmount: Float
  """The name of the tax rate."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The postal code the tax applies in."""
  postalCode: String
  """The rate, in percent."""
  rate: Float!
  """The state or region the tax applies in."""
  state: String
  """The kind of tax."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  """When the tax starts to apply."""
  validFrom: DateTime
  """When the tax stops applying."""
  validTo: DateTime
}

"""Filters and sorting for the tax rate list."""
input TaxRateFiltersInput {
  """Only tax rates in this city."""
  city: String
  """Only tax rates in this country."""
  country: String
  "Whether the record is active."
  isActive: Boolean
  "Whether this is the default."
  isDefault: Boolean
  "Text to search for."
  search: String
  """The column to sort by. Defaults to country, state, then name."""
  sortBy: TaxRateSortField
  """The sort direction."""
  sortOrder: SortOrder
  """Only tax rates in this state or region."""
  state: String
  """Only tax rates of this kind."""
  type: TaxType
}

"""A column the tax rate list can be sorted by."""
enum TaxRateSortField {
  """The rate code."""
  CODE
  """The country."""
  COUNTRY
  """When the rate was created."""
  CREATED_AT
  """The rate name."""
  NAME
  """The percentage."""
  RATE
}

"""
Totals for the tax rate list and its filter choices, over the whole set.
"""
type TaxRateSummary {
  """How many are active."""
  activeTaxRates: Int!
  """The mean rate in percent across live rates. 0 when there are none."""
  averageRate: Float!
  """The countries that have at least one live rate, A to Z."""
  countries: [String!]!
  """How many rates were updated in the last seven days."""
  recentlyUpdated: Int!
  """How many tax rates there are."""
  totalTaxRates: Int!
  """The tax kinds that have at least one live rate, A to Z."""
  types: [TaxType!]!
}

"""
The kind of tax, for example VAT, GST, SALES_TAX, or one of the Indian GST components CGST, SGST, IGST, UTGST and CESS.
"""
enum TaxType {
  """A tax on carbon emissions."""
  CARBON_TAX
  """A cess levied on top of another tax."""
  CESS
  """Central goods and services tax."""
  CGST
  """Corporate income tax."""
  CORPORATE
  """Customs duty."""
  CUSTOMS
  """A tax on entertainment."""
  ENTERTAINMENT_TAX
  """An environmental levy."""
  ENVIRONMENTAL
  """An excise tax."""
  EXCISE
  """A duty on exports."""
  EXPORT_DUTY
  """Goods and services tax."""
  GST
  """Integrated goods and services tax."""
  IGST
  """A duty on imports."""
  IMPORT_DUTY
  """A tax on luxury goods."""
  LUXURY_TAX
  """A tax on professions."""
  PROFESSIONAL_TAX
  """A tax on property."""
  PROPERTY_TAX
  """A registration fee."""
  REGISTRATION_FEE
  """A sales tax."""
  SALES_TAX
  """A tax on services."""
  SERVICE_TAX
  """State goods and services tax."""
  SGST
  """Stamp duty."""
  STAMP_DUTY
  """A tax based on tonnage."""
  TONNAGE_TAX
  """A tax on turnover."""
  TURNOVER_TAX
  """Union territory goods and services tax."""
  UTGST
  """Value added tax."""
  VAT
  """A tax withheld at source."""
  WITHHOLDING
}

"""Email engagement across all of your organization's document emails."""
type TenantEmailAnalytics {
  """Average hours customers took to reply. Null with no replies."""
  avgResponseTimeHours: Float
  """Clicked emails as a percentage of delivered."""
  clickRate: Float
  """Delivered emails as a percentage of sent."""
  deliveryRate: Float
  """Opened emails as a percentage of delivered."""
  openRate: Float
  """Replies as a percentage of delivered."""
  replyRate: Float
  """Emails with at least one link click."""
  totalEmailsClicked: Int!
  """Emails delivered."""
  totalEmailsDelivered: Int!
  """Emails opened at least once."""
  totalEmailsOpened: Int!
  """Emails sent."""
  totalEmailsSent: Int!
  """Replies received."""
  totalRepliesReceived: Int!
}

"""Your organization's document email settings and lifetime totals."""
type TenantEmailSettings {
  """Average hours customers took to reply. Null with no replies."""
  avgResponseTimeHours: Float
  "When the record was created."
  createdAt: DateTime!
  """Text appended to the sender name on outgoing emails."""
  fromNameSuffix: String!
  "The unique ID of this record."
  id: ID!
  """When the latest email was sent."""
  lastEmailSentAt: DateTime
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The address customer replies are routed to. Null when not set."""
  quoteReplyEmail: String
  """Whether quotes can be sent by email."""
  quoteSendingEnabled: Boolean!
  """Emails with at least one link click."""
  totalEmailsClicked: Int!
  """Emails delivered."""
  totalEmailsDelivered: Int!
  """Emails opened at least once."""
  totalEmailsOpened: Int!
  """Emails sent."""
  totalEmailsSent: Int!
  """Replies received."""
  totalRepliesReceived: Int!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""
One of the organization's own dated exchange rates. The rate is an exact decimal string meaning 1 unit of the foreign currency equals the rate in the base currency.
"""
type TenantExchangeRate {
  "When the record was created."
  createdAt: DateTime!
  """When the rate starts to apply."""
  effectiveFrom: DateTime!
  """Exclusive end; null = in force until replaced or ended"""
  effectiveTo: DateTime
  """The currency being converted from."""
  fromCurrency: String!
  "The unique ID of this record."
  id: ID!
  """A note on why the rate was set."""
  note: String
  """
  Exact decimal, e.g. "20.12345"
  """
  rate: String!
  """
  IN_FORCE (what new documents use now) | SUPERSEDED (in its window but a later-starting rate wins) | SCHEDULED | ENDED | WITHDRAWN (a scheduled rate removed before it applied; only ever returned by endTenantExchangeRate)
  """
  status: String!
  """The organization's base currency."""
  toCurrency: String!
}

"""
One foreign currency of the organization against its base currency: the global feed's current rate beside the organization's own rate in force, if any.
"""
type TenantExchangeRatePair {
  """The foreign currency."""
  fromCurrency: String!
  """The current rate from the global feed."""
  globalRate: Float
  """When the global rate was taken."""
  globalRateAsOf: DateTime
  """Where the global rate came from."""
  globalRateSource: String
  """The tenant's rate new documents use now, if one is in force"""
  inForce: TenantExchangeRate
  """The organization's base currency."""
  toCurrency: String!
}

"""The organization's exchange rate settings."""
type TenantExchangeRateSettings {
  """Org base currency code; empty when none is configured"""
  baseCurrency: String!
  """
  One entry per foreign currency, with the global rate beside the organization's own rate.
  """
  pairs: [TenantExchangeRatePair!]!
  """Every live tenant rate, newest start first per pair"""
  rates: [TenantExchangeRate!]!
}

"""A setting of the organization."""
type TenantSetting {
  """The group the setting is in."""
  category: SettingCategory!
  "When the record was created."
  createdAt: DateTime!
  """The data type of the value."""
  dataType: SettingDataType!
  """What the setting does."""
  description: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """The key of the setting."""
  key: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """A rule the value must follow."""
  validationRule: String
  """The value."""
  value: JSON
}

"""Filters for the settings list."""
input TenantSettingFilterInput {
  """Filter on the group."""
  category: StringFilter
  """Filter on when the record was created."""
  createdAt: DateFilter
  """Filter on the data type."""
  dataType: StringFilter
  """Filter on when the record was deleted."""
  deletedAt: DateFilter
  """Filter on the ID."""
  id: StringFilter
  """Filter on whether the setting is active."""
  isActive: BooleanFilter
  """Filter on whether the setting is a default."""
  isDefault: BooleanFilter
  """Filter on the key."""
  key: StringFilter
  """Global search across multiple fields"""
  search: String
  """Filter on when the record was last changed."""
  updatedAt: DateFilter
}

"""Set exactly one of controlId or rule."""
input TestControlOnRecordInput {
  """A saved control."""
  controlId: ID
  """The ID of the record to test on."""
  documentId: ID!
  """The record's type, e.g. SalesOrder."""
  documentType: String!
  """An unsaved rule."""
  rule: SaveControlInput
}

"""Sends a test email with the saved settings."""
input TestEmailConfigInput {
  """The text of the test email."""
  message: String
  """The subject of the test email."""
  subject: String
  """The address to send the test to."""
  testEmail: String!
}

"""The result of a test email."""
type TestEmailResult {
  """A message about the outcome."""
  message: String!
  """True when the test email was sent."""
  success: Boolean!
}

"""A time zone the organization can use."""
type Timezone {
  """The short name, for example GMT."""
  abbreviation: String
  """The IANA time zone code, for example Europe/London."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """A description of the time zone."""
  description: String
  """When daylight saving time ends."""
  dstEnd: String
  """The offset during daylight saving time."""
  dstOffset: String
  """When daylight saving time starts."""
  dstStart: String
  """True when it observes daylight saving time."""
  dstSupported: Boolean!
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Whether this is the default."
  isDefault: Boolean!
  """The name of the time zone."""
  name: String!
  """The offset from UTC."""
  offset: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The regions it covers."""
  regions: [String!]
  """The position in lists, lowest first."""
  sortOrder: Int!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""A customer who bought a lot."""
type TopCustomer {
  "The ID of the customer."
  customerId: String!
  """The name of the customer."""
  customerName: String!
  """How many orders the customer placed."""
  totalOrders: Int!
  """The revenue from the customer."""
  totalRevenue: Float!
}

"""A customer who brings in a lot of revenue."""
type TopCustomerRevenue {
  "The ID of the customer."
  customerId: String!
  """The name of the customer."""
  customerName: String!
  """The date of the last order."""
  lastOrderDate: DateTime
  """How many orders the customer placed."""
  orderCount: Int!
  """The revenue from the customer."""
  totalRevenue: Float!
}

"""An item that moves fast."""
type TopMovingItem {
  """How many days the stock on hand will last at the current pace."""
  daysOfSupply: Int!
  """How much of it moved."""
  movement: Float!
  "The ID of the product."
  productId: String!
  """The name of the product."""
  productName: String!
}

"""A product that sold a lot."""
type TopProduct {
  "The ID of the product."
  productId: String!
  """The name of the product."""
  productName: String!
  """How many units were sold."""
  quantity: Float!
  """The revenue from the product."""
  revenue: Float!
}

"""A product bought a lot."""
type TopPurchaseProduct {
  "The ID of the product."
  productId: String!
  """The name of the product."""
  productName: String!
  """How many units were bought."""
  quantity: Float!
  """The value bought."""
  value: Float!
}

"""A supplier bought from a lot."""
type TopSupplier {
  "The ID of the supplier."
  supplierId: String!
  """The name of the supplier."""
  supplierName: String!
  """How many purchase orders were raised."""
  totalOrders: Int!
  """The value bought."""
  totalValue: Float!
}

"""A transfer of stock from one warehouse to another."""
input TransferInventoryInput {
  """The ID of the warehouse the stock leaves."""
  fromWarehouseId: ID!
  """
  A unique key. Sending the same key again returns the transfer already made instead of a second one.
  """
  idempotencyKey: String
  """The lines to transfer."""
  items: [TransferItemInput!]!
  """Notes about the transfer."""
  notes: String
  """Why the stock is transferred."""
  reason: String
  """The ID of the warehouse the stock goes to."""
  toWarehouseId: ID!
}

"""One line of a stock transfer."""
input TransferItemInput {
  """The batch to move."""
  batchNumber: String
  """The cost of one unit."""
  cost: Float
  """Notes about the line."""
  notes: String
  "The ID of the product."
  productId: ID!
  """The quantity to move. Must be greater than zero."""
  quantity: Float!
  """The serial number to move."""
  serialNumber: String
  "The ID of the product variant."
  variantId: ID!
}

"""The kind of internal transfer a return between warehouses is."""
enum TransferType {
  """Moved to another branch."""
  BRANCH_TRANSFER
  """Moved to another department."""
  DEPARTMENT_TRANSFER
  """Sent to quality control."""
  QUALITY_RETURN
}

"""A value and its growth for one period."""
type TrendData {
  """The growth against the previous period, in percent."""
  growth: Float!
  """The period."""
  period: String!
  """The value."""
  value: Float!
}

"""Values for one bucket of time."""
type TrendPoint {
  """The bucket, for example a day or month."""
  bucket: String!
  """The value collected."""
  collected: Float!
  """The value invoiced."""
  invoiced: Float!
  """The value of orders."""
  orders: Float!
  """The value of quotes."""
  quotes: Float!
}

"""Logins for one bucket of time."""
type TrendPoint2 {
  """The bucket, for example a day or month."""
  bucket: String!
  """How many logins."""
  logins: Int!
}

"""Trends in sales."""
type TrendsAnalytics {
  """How each category's sales are moving."""
  categoryTrends: [CategoryTrend!]!
  """How each product's sales are moving."""
  productTrends: [ProductTrend!]!
  """Sales over time."""
  salesTrend: [TrendData!]!
  """How sales behave by season."""
  seasonalTrends: [SeasonalTrend!]!
}

"""A home section showing a rail of trusted brand logos."""
type TrustedBrandsRailSection {
  """The brand logos."""
  brands: [HomeBrandLogoCell!]!
  """The kind of home section."""
  kind: HomeSectionKind!
  """The title of the section."""
  title: String
}

"""What a user needs to finish setting up two-factor sign in."""
type TwoFactorSetupResponse {
  """One-time codes to use if the app is not available."""
  backupCodes: [String!]!
  """The QR code to scan in the authenticator app."""
  qrCode: String!
}

"""Whether two-factor sign in is on."""
type TwoFactorStatusResponse {
  """True when two-factor sign in is on."""
  enabled: Boolean!
  """True when backup codes are available."""
  hasBackupCodes: Boolean!
  """When two-factor was last used."""
  lastUsed: DateTime
}

"""
The kind of quantity a unit measures. Units convert only within a category.
"""
enum UOMCategory {
  """Area."""
  AREA
  """
  Items counted as whole numbers. Always 0 decimal places and no fractions.
  """
  COUNT
  """
  Any other unit. Units created from a name, such as in a product import, get this category.
  """
  CUSTOM
  """Length or distance."""
  LENGTH
  """Temperature."""
  TEMPERATURE
  """Time or duration."""
  TIME
  """Volume or capacity."""
  VOLUME
  """Weight or mass."""
  WEIGHT
}

"""
A conversion between two units of the same category. Creating one also creates the reverse conversion.
"""
type UOMConversion {
  """
  Multiply a quantity in the from unit by this to get the quantity in the to unit.
  """
  conversionFactor: Float!
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  """Optional formula text recorded for the conversion."""
  formula: String
  """The unit converted from."""
  fromUOM: UnitOfMeasure!
  """The ID of the unit converted from."""
  fromUOMId: ID!
  "The unique ID of this record."
  id: ID!
  """The ID of the reverse conversion that was created with this one."""
  inverseFactorId: String
  "Whether the record is active."
  isActive: Boolean!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The unit converted to."""
  toUOM: UnitOfMeasure!
  """The ID of the unit converted to."""
  toUOMId: ID!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""Filters and sorting for the list of units."""
input UOMFiltersInput {
  """Only units in this category."""
  category: UOMCategory
  """Only active units (true) or only inactive units (false)."""
  isActive: Boolean
  """Only base units (true) or only non-base units (false)."""
  isBase: Boolean
  """Text to search for in units."""
  search: String
  """Field to sort by. Omitted means display order, then name."""
  sortBy: UOMSortField
  """Sort direction."""
  sortOrder: SortOrder
}

"""Fields the list of units can be sorted by."""
enum UOMSortField {
  """The unit's category."""
  CATEGORY
  """The unit's code."""
  CODE
  """When the unit was created."""
  CREATED_AT
  """The unit's display order."""
  DISPLAY_ORDER
  """The unit's name."""
  NAME
}

"""Counts and highlights for the unit-of-measure settings page."""
type UOMSummary {
  """Number of active units."""
  activeUOMs: Int!
  """The base unit of each category that has one."""
  baseUOMs: [UnitOfMeasure!]!
  """Number of inactive units."""
  inactiveUOMs: Int!
  """When the summary was calculated."""
  lastUpdated: DateTime!
  """The five most recently created units."""
  recentUOMs: [UnitOfMeasure!]!
  """Total number of conversions."""
  totalConversions: Int!
  """Total number of units."""
  totalUOMs: Int!
  """The number of units in each category."""
  uomsByCategory: [UOMsByCategory!]!
  """
  variants with MORE than 3 sellable ProductUOM rows — created before the ≤3 cap existed. Report-only (not auto-fixed); admins should trim these down.
  """
  variantsOverSellableCap: Int!
}

"""The number of units in one category."""
type UOMsByCategory {
  """The unit category."""
  category: UOMCategory!
  """Number of units in the category."""
  count: Int!
}

"""A delivery partner that could not give a price, and why."""
type UnavailableDeliveryPartnerGql {
  """
  The courier inside an aggregator that refused. Empty when the whole partner did.
  """
  carrierName: String
  """
  A machine-readable reason, for example NO_PRICE, TIMEOUT or COUNTRY_NOT_SERVED.
  """
  code: String
  """The ID of the delivery partner."""
  deliveryPartnerConfigId: String!
  """The name of the delivery partner."""
  partnerDisplayName: String!
  """The exact reason, in English."""
  reason: String!
  """True when asking again may succeed."""
  retryable: Boolean
}

"""
A unit of measure in the organization's catalog, with its category, decimal rules and display settings.
"""
type UnitOfMeasure {
  """
  Whether quantities in this unit may be fractional. Always false for a COUNT unit.
  """
  allowFractional: Boolean!
  """
  The kind of quantity the unit measures. Units convert only within a category.
  """
  category: UOMCategory!
  """
  Short code that identifies the unit. It is unique in the organization, ignoring case.
  """
  code: String!
  """Colour code used to show the unit."""
  colorCode: String
  """The ID of the unit this unit combines with in compound quantities."""
  compoundWithUOMId: String
  """Conversions that start at this unit."""
  conversionFrom: [UOMConversion!]
  """Conversions that end at this unit."""
  conversionTo: [UOMConversion!]
  "When the record was created."
  createdAt: DateTime!
  """
  How many decimal places quantities in this unit show, from 0 to 6. Always 0 for a COUNT unit.
  """
  decimalPlaces: Int!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """Free-text description of the unit."""
  description: String
  """Position of the unit in lists. Lower numbers come first."""
  displayOrder: Int!
  "The ID of the user who created the record."
  enteredBy: String!
  """URL of the unit's icon image."""
  iconUrl: String
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """
  Whether this is the base unit of its category. A category has one base unit.
  """
  isBase: Boolean!
  """The unit's name."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """Plural form of the name, when it needs one."""
  pluralName: String
  """Whether the unit is shown in compound quantities."""
  showInCompound: Boolean!
  """Symbol shown next to quantities in this unit."""
  symbol: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
}

"""Removes a device from push messages."""
input UnregisterPushTokenInput {
  """The ID of the device."""
  deviceId: ID!
}

"""
Changes to a bank account. Omitted fields stay as they are. The balance cannot be edited here, use adjustBankAccountBalance.
"""
input UpdateBankAccountInput {
  """The name the account is known by in the organization."""
  accountName: String
  """The account number."""
  accountNumber: String
  """
  The kind of account, for example CURRENT or SAVINGS. Defaults to CURRENT.
  """
  accountType: String
  """The name of the bank that holds the account."""
  bankName: String
  """The bank branch or sort code."""
  branchCode: String
  "ISO 4217 currency code."
  currencyCode: String
  """The IBAN."""
  iban: String
  "Whether the record is active."
  isActive: Boolean
  "Whether this is the default."
  isDefault: Boolean
  """Free-text notes about the account."""
  notes: String
  """The SWIFT or BIC code of the bank."""
  swiftCode: String
}

"""Changes to a brand. Omitted fields stay as they are."""
input UpdateBrandInput {
  """The brand code."""
  code: String
  """What the brand is."""
  description: String
  "Whether the record is active."
  isActive: Boolean
  """The URL of the brand logo."""
  logoUrl: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The name of the brand."""
  name: String
  """The brand's website."""
  websiteUrl: String
}

"""Changes an item in the cart."""
input UpdateCartItemInput {
  """
  Buyer consent: if this item becomes unavailable, may fulfillment ship a manually-picked substitute instead? Set once at cart time; carries forward automatically through Quote/SalesOrder/Invoice.
  """
  acceptAlternativeIfUnavailable: Boolean
  """The ID of the cart item."""
  cartItemId: ID!
  """CAS guard: the cart revision this mutation was read against."""
  expectedRevision: Int
  """A note on the line."""
  notes: String
  """Client-minted id for replay-safety (same id+payload = no-op success)."""
  operationId: String
  """
  The new quantity. Must be greater than zero. Use the remove mutation to remove a line.
  """
  quantity: Float!
}

"""Changes to a category. Omitted fields stay as they are."""
input UpdateCategoryInput {
  """The new code."""
  code: String
  """The new description."""
  description: String
  """The ID of the category to change."""
  id: ID!
  """The new image URL."""
  imageUrl: String
  "Whether the record is active."
  isActive: Boolean
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The new name."""
  name: String
  """The ID of the new parent category."""
  parentId: String
  """The new position among sibling categories."""
  sortOrder: Int
}

"""Changes to a chat channel. Omitted fields stay as they are."""
input UpdateChannelInput {
  """The new description."""
  description: String
  """The new name."""
  name: String
}

"""Changes to a chat conversation."""
input UpdateConversationInput {
  """The new title."""
  title: String!
}

"""Changes a proposal before it is applied."""
input UpdateCopilotProposalInput {
  """The new proposed change."""
  payload: JSON!
  """The ID of the proposal."""
  proposalId: ID!
}

"""
Changes to a credit note. Omitted fields stay as they are. A note whose lines follow a return's inspection cannot have its lines changed.
"""
input UpdateCreditNoteInput {
  """A signed adjustment to the total, such as rounding."""
  adjustments: Float
  """The note amount before tax."""
  amount: Float!
  "ISO 4217 currency code."
  currency: String!
  """The date after which the credit can no longer be applied."""
  expiryDate: DateTime
  """Notes for staff only. They are not shown to the customer or supplier."""
  internalNotes: String
  """The credit lines."""
  items: [UpdateCreditNoteItemInput!]!
  """Notes shown on the note."""
  notes: String
  """The ID of the invoice the note is raised against."""
  originalInvoiceId: String
  "The ID of the partner."
  partnerId: String!
  """Why the note is raised."""
  reason: String!
  """The ID of the return the note comes from."""
  returnId: String
  """The tax on the note."""
  taxAmount: Float
  """
  What the note is for: SALES_RETURN, PURCHASE_RETURN, PRICE_ADJUSTMENT, GOODWILL or OTHER.
  """
  type: String!
}

"""One line of a credit note being changed."""
input UpdateCreditNoteItemInput {
  """The line amount."""
  amount: Float!
  """What the credit is for on this line."""
  description: String!
  """The discount on the line, rounded to the currency."""
  discountAmount: Float
  """
  The exact discount for the full line quantity, before rounding. When left out it is worked out from the percent and the amount.
  """
  discountAmountExact: Float
  """The discount on the line, in percent."""
  discountPercent: Float
  "The ID of the product."
  productId: String
  """The quantity credited."""
  quantity: Float!
  """The tax on the line."""
  taxAmount: Float
  """The tax split as a list of tax type, rate and tax amount."""
  taxBreakdown: JSON
  """The tax rate on the line, in percent."""
  taxRate: Float
  """The price of one unit."""
  unitPrice: Float!
  "The ID of the product variant."
  variantId: String
}

"""Changes to a currency. Omitted fields stay as they are."""
input UpdateCurrencyInput {
  """The currency code, such as an ISO 4217 code."""
  code: String
  """How many decimal places amounts show."""
  decimalPlaces: Int
  """The character between the whole and decimal parts."""
  decimalSeparator: String
  "Whether the record is active."
  isActive: Boolean
  """True when this is the organization's base currency."""
  isBaseCurrency: Boolean
  """The name of the currency."""
  name: String
  """The position in lists, lowest first."""
  sortOrder: Int
  """The currency symbol."""
  symbol: String
  """Where the symbol goes: before or after the amount."""
  symbolPosition: String
  """The character between thousands."""
  thousandSeparator: String
  """The kind of currency: fiat, crypto or commodity."""
  type: String
  """The ID of the user who changed it."""
  updatedBy: String
}

"""Changes to a customer collection. Omitted fields stay as they are."""
input UpdateCustomerCollectionInput {
  """The new amount, in the collection's currency. Must be positive."""
  amount: Float
  """The ID of the bank account that received the money."""
  bankAccountId: ID
  """The new date the money was received."""
  collectionDate: DateTime
  """The new way the customer paid."""
  collectionMethod: CollectionMethod
  "ISO 4217 currency code."
  currency: String
  """The new exchange rate to the organization's base currency."""
  exchangeRate: Float
  """Free-text notes about the collection."""
  notes: String
  """The customer's reference for the payment."""
  referenceNumber: String
}

"""Changes to a customer. Omitted fields stay as they are."""
input UpdateCustomerInput {
  """The city."""
  addressCity: String
  """The country."""
  addressCountry: String
  """The postal code."""
  addressPostalCode: String
  """The state or region."""
  addressState: String
  """The first line of the street address."""
  addressStreet1: String
  """The second line of the street address."""
  addressStreet2: String
  """True to also create the customer as a vendor, using the vendor terms."""
  alsoCreateAsVendor: Boolean
  """
  The ID of the sales rep the customer is assigned to. Admins may set it. For a sales rep creating the customer, the server sets it to that rep.
  """
  assignedSalesRepId: String
  """The customer's business category."""
  businessCategory: String
  """How the customer buys."""
  buyingProcess: String
  """The customer's certifications."""
  certifications: [String!]
  """How the customer prefers to be contacted."""
  communicationPreference: String
  """The size of the customer's company."""
  companySize: String
  """The email address of the main contact."""
  contactEmail: String
  """The name of the main contact."""
  contactName: String
  """The phone number of the main contact."""
  contactPhone: String
  """The credit limit. 0 or less means unlimited."""
  creditLimit: Int
  """The customer's credit rating."""
  creditRating: String
  """The customer's business type."""
  customerType: String
  """Who makes the buying decision."""
  decisionMaker: String
  """What the customer is."""
  description: String
  """The name to show for the customer."""
  displayName: String
  """The ID of the customer to change."""
  id: ID!
  """The customer's industry."""
  industry: String
  """
  The vendor's expected days from order to delivery, when also created as a vendor.
  """
  leadTimeDays: Int
  """The legal name of the customer."""
  legalName: String
  """The customer's loyalty points."""
  loyaltyPoints: Int
  """The customer's loyalty tier."""
  loyaltyTier: String
  """True when the customer agreed to marketing messages."""
  marketingOptIn: Boolean
  """The smallest order value the customer may place."""
  minimumOrderValue: Int
  """The name of the customer."""
  name: String
  """Notes about the customer."""
  notes: String
  """The payment terms agreed with the customer."""
  paymentTerms: String
  """
  The currency of the customer's documents. Leave out to use the organization's default.
  """
  preferredCurrency: String
  """The customer's preferred shipping method."""
  preferredShippingMethod: String
  """The product categories the customer deals in."""
  productCategories: [String!]
  """The customer's company registration number."""
  registrationNumber: String
  """When the customer's buying peaks."""
  seasonality: String
  """The areas the customer serves."""
  serviceAreas: [String!]
  """Special instructions for handling the customer."""
  specialInstructions: String
  """Tags on the customer."""
  tags: [String!]
  """The customer's tax ID."""
  taxId: String
  """The kind of customer."""
  type: String
  """The kind of vendor, when also created as a vendor."""
  vendorType: String
  """The customer's website."""
  website: String
}

"""Changes to the customer discount tier setup."""
input UpdateCustomerTierConfigInput {
  """True to switch automatic tiering on."""
  enabled: Boolean!
  """The tiers to save."""
  tiers: [CustomerTierConfigItemInput!]!
}

"""Changes to one customer login, made by the seller."""
input UpdateCustomerUserInput {
  """
  granted branch address ids (required ≥ 1 when scope = BRANCH). Full-array replace of this user's PartnerBranchApprover rows.
  """
  approverBranchAddressIds: [ID!]
  """True when the person approves orders."""
  approvesOrders: Boolean
  """
  The FULL set of addresses assigned to this user (PartnerBranchMember). Any live address of the partner is assignable — it need not be a branch. Full-array replace — OMIT to leave assignments untouched; [] clears them, which returns the user to the whole address book (unrestricted), not to none.
  """
  assignedAddressIds: [ID!]
  """approver scope — COMPANY | BRANCH."""
  customerApproverScope: String
  """The person's first name."""
  firstName: String
  """The person's last name."""
  lastName: String
  """Per-order ceiling; null clears it (no limit). Must be > 0."""
  orderLimit: Float
  """CUSTOMER_ADMIN (Owner) | CUSTOMER_BUYER | CUSTOMER_VIEWER."""
  role: String
  "The ID of the user."
  userId: ID!
}

"""
Changes to a debit note that is still pending. Omitted fields stay as they are.
"""
input UpdateDebitNoteInput {
  """The new signed adjustment to the total."""
  adjustments: Float
  """The new amount before tax."""
  amount: Float
  """The new due date."""
  dueDate: String
  """Notes for staff only."""
  internalNotes: String
  """Notes shown on the note."""
  notes: String
  """The new tax on the note."""
  taxAmount: Float
}

"""
Changes to what customers see for delivery. Omitted fields keep the saved value. A list that is given replaces the saved list whole.
"""
input UpdateDeliveryCustomerDisplayInput {
  """The services customers may or may not be offered."""
  allowedServices: [DeliveryAllowedServiceInput!]
  """The customer surfaces the shaping applies to."""
  applyTo: CustomerDeliveryApplyToInput
  """The rule that picks the option in AUTO mode."""
  autoRule: DeliveryAutoRule
  """How customers choose delivery: LIST, SPEEDS or AUTO."""
  choiceMode: DeliveryChoiceMode
  """
  What happens to a service a partner starts returning: OFFER it or HOLD it until staff decide.
  """
  newServicePolicy: DeliveryNewServicePolicy
  """What the sales app shows about delivery."""
  salesApp: SalesAppDeliveryView
  """Which delivery details customer screens show."""
  show: CustomerDeliveryDetailsInput
  """The delivery speeds customers can pick in SPEEDS mode."""
  speeds: [DeliverySpeedInput!]
  """How much tracking detail customers see."""
  tracking: CustomerTrackingLevel
}

"""
Changes to the packing settings. Omitted fields keep their saved value. A boxes list replaces the saved list, and a null freightQuoteAboveKg switches the freight quote off.
"""
input UpdateDeliveryPackingSettingsInput {
  """The box types available for packing."""
  boxes: [DeliveryPackingBoxInput!]
  """The size and weight assumed for an item that has none of its own."""
  defaultItem: DeliveryPackingItemDefaultsInput
  """How full a box may be packed, in percent."""
  fillPercent: Float
  """How full a box of fragile items can be packed (%)."""
  fragileFillPercent: Float
  """The packed weight above which a freight quote is needed, in kilograms."""
  freightQuoteAboveKg: Float
  """
  Most boxes an order may pack into and still be live-quoted; null switches it off.
  """
  maxBoxesPerOrder: Int
  """True when customers see how many boxes their order packs into."""
  showBoxCountToCustomers: Boolean
  """The measurement system the console shows and accepts."""
  units: PackingMeasurementSystem
  """The divisor that turns box volume into volumetric weight."""
  volumetricDivisor: Int
}

"""Changes to the delivery settings."""
input UpdateDeliverySettingsInput {
  """
  Deprecated and not read: a carrier's delivered report always marks the order delivered.
  """
  autoDeliverFromCarrier: Boolean @deprecated(reason: "Always on: a carrier's delivered marks the order delivered (D-127). Not read.")
  """True to email the customer when an outbound shipment is delivered."""
  customerEmailOnDelivered: Boolean
  """True to email the customer when an outbound shipment is booked."""
  customerEmailOnShipped: Boolean
  """
  Deprecated: the parcel size and weight to quote with when none is given. The Default box replaces it.
  """
  defaultParcel: DeliveryParcelInput @deprecated(reason: "Set a Default box in updateDeliveryPackingSettings instead. Omitted = unchanged.")
  """
  Deprecated and not read: the warehouse shipments were collected from by default.
  """
  defaultPickupWarehouseId: String @deprecated(reason: "Not read: couriers collect from the order line's warehouse, else the Inventory default warehouse.")
  """
  How the delivery fee is worked out: a flat fee or a live quote from the delivery partners.
  """
  feeMode: DeliveryFeeMode!
  """
  The flat delivery fee, as a decimal string in the organization's base currency.
  """
  flatFee: String
  """
  The order total at or above which delivery is free, as a decimal string. Empty means no threshold.
  """
  freeDeliveryThreshold: String
  """
  The order total at or above which live-quoted delivery is free, as a decimal string. Empty means no threshold.
  """
  liveQuoteFreeThreshold: String
  """
  The default layout of the shipping sticker. Leave out to keep the saved one.
  """
  stickerFormat: ShipmentStickerFormat
  """
  The height of the custom sticker size, in whole millimetres. Null clears it. Leave out to keep the saved one.
  """
  stickerHeightMm: Int
  """
  The width of the custom sticker size, in whole millimetres. Null clears it. Leave out to keep the saved one.
  """
  stickerWidthMm: Int
}

"""Changes to a discount scheme. Omitted fields stay as they are."""
input UpdateDiscountSchemeDto {
  """The customer types the scheme applies to."""
  applicableCustomerTypes: String
  """The regions the scheme applies to."""
  applicableRegions: String
  """For a buy-and-get scheme, how many to buy."""
  buyQuantity: Float
  """
  The ID of the currency the scheme is for. Empty means the base currency.
  """
  currencyId: String
  """What the scheme is for."""
  description: String
  """The rules that set the discount."""
  discountRules: [CreateDiscountRuleDto!]
  """The fixed discount amount."""
  fixedAmountValue: Float
  "Whether the record is active."
  isActive: Boolean
  """True when the scheme can combine with other discounts."""
  isStackable: Boolean
  """The most times the scheme may be used in all."""
  maxUsageCount: Int
  """The most times one customer may use the scheme."""
  maxUsagePerCustomer: Int
  """The smallest order amount the scheme applies to."""
  minOrderAmount: Float
  """The name of the scheme."""
  name: String
  """The discount in percent."""
  percentageValue: Float
  """Which scheme wins when several apply. Higher goes first."""
  priority: Int
  """What the scheme applies to."""
  scope: DiscountScope
  """When the scheme starts."""
  validFrom: String
  """When the scheme ends."""
  validUntil: String
}

"""
Creates or updates the organization's wording for one type of document email. The organization comes from the sign in.
"""
input UpdateDocumentEmailCopyInput {
  """The body paragraph."""
  body: String
  """The kind of document email."""
  emailType: String!
  """The subject line."""
  subject: String
}

"""Changes to the number series of one document type."""
input UpdateDocumentNumberSeriesInput {
  """The date part of the number, if any."""
  dateFormat: String
  """The kind of document."""
  docType: DocumentNumberType!
  """
  Continue the series from this number (e.g. when migrating from another system). Must be above the last number issued.
  """
  nextNumber: Int
  """How many digits the running number is padded to."""
  padWidth: Int
  """The prefix of the numbers."""
  prefix: String
  """
  When the running number starts again, for example never, yearly or monthly.
  """
  resetPolicy: String
  """The character between the parts of the number."""
  separator: String
}

"""
Saves a document template setup. It needs the settings:documents:update permission.
"""
input UpdateDocumentTemplateConfigInput {
  """The accent colour."""
  accentColor: String
  """The company address printed on the document."""
  companyAddress: String
  """The company name printed on the document."""
  companyName: String
  """The kind of document the template is for."""
  documentType: String!
  """The footer text printed on the document."""
  footerText: String
  """Inline base64 data URL (data:image/...), or "" to clear"""
  logoAssetKey: String
  """The layout style of the document."""
  style: String
  """The terms printed on the document."""
  terms: String
  """The columns shown in the line items table."""
  visibleColumns: [String!]
}

"""
Changes to the organization's email settings. Omitted fields stay as they are.
"""
input UpdateEmailConfigInput {
  """The provider API key. It is write-only."""
  apiKey: String
  """The time of day the daily report is sent."""
  dailyReportTime: String
  """The addresses reports and alerts go to by default."""
  defaultRecipients: [String!]
  """The signature added to mail."""
  emailSignature: String
  """The address mail is sent from."""
  fromEmail: String
  """The name mail is sent from."""
  fromName: String
  """True when sending is switched on."""
  isEnabled: Boolean
  """The day of the month the monthly report is sent."""
  monthlyReportDate: Int
  """
  The email provider: SMTP, SENDGRID, AWS_SES, MAILGUN, RESEND or GOOGLE.
  """
  provider: EmailProvider
  """The address replies go to."""
  replyToEmail: String
  """True to send alert emails."""
  sendAlerts: Boolean
  """True to send notification emails."""
  sendNotifications: Boolean
  """True to send report emails."""
  sendReports: Boolean
  """The SMTP server."""
  smtpHost: String
  """The SMTP password. It is write-only."""
  smtpPassword: String
  """The SMTP port."""
  smtpPort: Int
  """True to use a secure connection."""
  smtpSecure: Boolean
  """The SMTP user name."""
  smtpUser: String
  """The day of the week the weekly report is sent."""
  weeklyReportDay: Int
}

"""Changes to a goods receipt. Omitted fields stay as they are."""
input UpdateGRNInput {
  "ISO 4217 currency code."
  currency: String
  """
  True when damage was reported on delivery. Leave out to keep it as it is.
  """
  damageReported: Boolean
  """The date the goods arrived. Defaults to now."""
  deliveryDate: String
  """The name of the driver who delivered the goods."""
  driverName: String
  """
  The rate to the organization's base currency: 1 unit of the receipt currency in the base currency. Needed when the currency is not the base currency.
  """
  exchangeRate: Float
  """The date the goods were expected."""
  expectedDate: String
  """The ID of the goods receipt to change."""
  id: ID!
  """When the goods were inspected."""
  inspectedAt: String
  """The ID of the user who inspected the goods."""
  inspectedBy: String
  """The lines received."""
  items: [CreateGRNItemInput!]
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """Notes about the receipt."""
  notes: String
  """
  The date the purchase order was placed. Used to work out the actual lead time.
  """
  orderDate: String
  "The ID of the purchase order."
  purchaseOrderId: String
  """An overall quality score for the delivery."""
  qualityScore: Float
  """A reference to the delivery document, such as a delivery note number."""
  receiptDocument: String
  """
  True when a shortage was reported on delivery. Leave out to keep it as it is.
  """
  shortageReported: Boolean
  """
  The receipt status, for example DRAFT, CONFIRMED, PARTIALLY_RECEIVED or RECEIVED. Leave out to keep it as it is.
  """
  status: String
  """The registration number of the delivery vehicle."""
  vehicleNumber: String
  """The ID of the vendor that delivered the goods."""
  vendorPartnerId: String
  "The ID of the warehouse."
  warehouseId: String
}

"""Changes to an integration setting. Omitted fields stay as they are."""
input UpdateIntegrationSettingInput {
  """The integration's configuration, as JSON."""
  config: JSON
  """What the integration is for."""
  description: String
  """The name to show for the integration."""
  displayName: String
  """The ID of the integration setting."""
  id: String!
  """True when the integration is switched on."""
  isEnabled: Boolean
  """Which integration wins when several do the same job."""
  priority: Int
  """The service the integration is for."""
  serviceName: IntegrationService
  """Tags on the integration."""
  tags: [String!]
  """The version of the integration."""
  version: String
  """The webhook address of the integration."""
  webhookUrl: String
}

"""
The stock alert thresholds of one stock row. Omitted fields stay as they are, and 0 clears a threshold.
"""
input UpdateInventoryThresholdsInput {
  """The ID of the stock row."""
  inventoryId: ID!
  """The days it takes to replenish the stock."""
  leadTimeDays: Float
  """The highest quantity the row should hold."""
  maximumQuantity: Float
  """The lowest quantity the row should hold."""
  minimumQuantity: Float
  """
  The quantity at which the row counts as low. Setting it by hand stops the automatic reorder engine from changing it.
  """
  reorderPoint: Float
  """
  How much to buy when the reorder point is reached. Advisory, nothing orders by itself.
  """
  reorderQuantity: Float
}

"""Changes to an invoice."""
input UpdateInvoiceInput {
  """Billing address, as JSON."""
  billingAddress: JSON
  """ISO 4217 currency code of the invoice."""
  currency: String
  """Additional invoice-level discount as an amount. Must not be negative."""
  discountAmount: Float
  """Payment due date, as an ISO 8601 date."""
  dueDate: String
  """
  Exchange rate to the organization's base currency: 1 unit of the invoice currency equals this many base units. Must be greater than zero.
  """
  exchangeRate: Float
  """
  Optimistic-concurrency check: the version this client read. Stale → typed VERSION_CONFLICT under COMMAND_CAS=enforce.
  """
  expectedVersion: Int
  """Notes for your team only, not shown to the customer."""
  internalNotes: String
  """The invoice date, as an ISO 8601 date."""
  invoiceDate: String
  """The invoice lines."""
  items: [UpdateInvoiceItemInput!]
  """Notes shown to the customer on the invoice."""
  notes: String
  """The ID of the customer or supplier."""
  partnerId: ID
  """
  Payment terms code. It is checked against your organization's configured terms.
  """
  paymentTerms: String
  """Shipping address, as JSON."""
  shippingAddress: JSON
  """Shipping charge. Must not be negative."""
  shippingAmount: Float
  """Move the invoice to this status."""
  status: InvoiceStatus
  """Surcharge. Must not be negative."""
  surchargeAmount: Float
  """Total tax on the invoice. Must not be negative."""
  taxAmount: Float
  """Whether prices include or exclude tax: INCLUSIVE or EXCLUSIVE."""
  taxCalculationMethod: String
  """
  Terms and conditions text printed on the invoice. Put the payment term code in paymentTerms, not here.
  """
  terms: String
}

"""One invoice line in an update."""
input UpdateInvoiceItemInput {
  """How many stock units one invoiced unit is worth. Must not be negative."""
  conversionFactor: Float
  """Description shown on the invoice line."""
  description: String!
  """
  The line discount as an amount. When sent it is used instead of re-deriving the amount from discountPercent. Must not be negative.
  """
  discountAmount: Float
  """Line discount as a percentage, from 0 to 100."""
  discountPercent: Float
  """
  The ID of the goods receipt line this purchase invoice line bills. Send it back unchanged to keep the link.
  """
  grnItemId: ID
  """The ID of the existing invoice line. Omit for a new line."""
  id: ID
  """The ID of the product being invoiced."""
  productId: ID!
  """
  Quantity invoiced, in the unit given by uomId. Must be greater than zero.
  """
  quantity: Float!
  """
  The ID of the sales order line this invoice line bills. Send it back unchanged to keep the link to the order.
  """
  salesOrderItemId: ID
  """Tax split by component, as JSON."""
  taxBreakdown: JSON
  """Tax rate for the line. Must not be negative."""
  taxRate: Float!
  """Price per unit. Must not be negative."""
  unitPrice: Float!
  """The ID of the unit of measure for the quantity."""
  uomId: ID
  """Name of the unit of measure, shown on the line."""
  uomName: String
  """The ID of the product variant being invoiced."""
  variantId: ID
  """The ID of the warehouse the goods ship from."""
  warehouseId: ID
}

"""Changes to a language. Omitted fields stay as they are."""
input UpdateLanguageInput {
  """The language code."""
  code: String
  """The default date format."""
  dateFormat: String
  """The writing direction: LTR or RTL."""
  direction: String
  "Whether the record is active."
  isActive: Boolean
  "Whether this is the default."
  isDefault: Boolean
  """The name of the language."""
  name: String
  """The name of the language in that language."""
  nativeName: String
  """The default time format."""
  timeFormat: String
}

"""Changes to a menu item. Omitted fields stay as they are."""
input UpdateMenuInput {
  """What the menu item is for."""
  description: String
  """The icon of the menu item."""
  icon: String
  """The ID of the menu item."""
  id: String!
  "Whether the record is active."
  isActive: Boolean
  """True when the item is a main menu entry."""
  isMainMenu: Boolean
  """The text shown for the menu item."""
  label: String
  """MAIN or SUB."""
  menuType: MenuType
  """The internal name of the menu item."""
  name: String
  """The position among its siblings, lowest first."""
  order: Int
  """The ID of the parent menu item."""
  parentId: String
  """The address the menu item opens."""
  path: String
  """The permissions needed to see the item."""
  requiredPermissions: [String!]
}

"""Changes to an ordering address. Omitted fields stay as they are."""
input UpdateMobileAddressInput {
  "The ID of the address."
  addressId: ID!
  """The first line of the address."""
  addressLine1: String
  """Address classification (AddressType enum)."""
  addressType: AddressType
  """The city."""
  city: String
  """The country."""
  country: String
  """
  TRUE when the address serves BOTH the shipping and billing role. `addressType` stays the PRIMARY classification (one enum column cannot hold two roles) and this records the second — the same pair `myAddresses` already returns. Nullable/optional: app builds predating this field send nothing and the column defaults to false. Until this existed the buyer app had nowhere to put a both-ticked selection, so it encoded the combination in `name` ("Shipping & Billing") and parsed it back out on edit — do not go back to that.
  """
  isDualPurpose: Boolean
  """The latitude of the address on the map."""
  lat: Float
  """The longitude of the address on the map."""
  lng: Float
  """The name of the address."""
  name: String
  "Phone number."
  phone: String
  """
  Postal / ZIP code. OPTIONAL, unlike the admin address form which requires it: many of the countries this app ships to (QA, AE, …) have no postal system, and a required field there blocks the buyer from saving a perfectly valid address. Omitted or blank stores an empty string — `Address.postalCode` is a NOT NULL column, so it can never be null. Until this field existed the service wrote the literal "00000" for every mobile-created address, which is why older rows carry it.
  """
  postalCode: String
  """The state or region."""
  state: String
}

"""Changes to a contact. Omitted fields stay as they are."""
input UpdateMobileContactInput {
  """The person's department."""
  department: String
  "Email address."
  email: String
  """The person's first name."""
  firstName: String
  """The ID of the contact."""
  id: ID!
  """The person's last name."""
  lastName: String
  """The person's full name, for callers that send one name."""
  name: String
  "Phone number."
  phone: String
  """The person's job title."""
  title: String
  """The person's WhatsApp number."""
  whatsapp: String
}

"""
Buyer 'edit items': the FULL list of lines to keep, with their new quantities. Lines not listed are removed; lines not already on the order are refused (v1 does not add products). No prices — the server re-prices every line.
"""
input UpdateMobileOrderItemsInput {
  """MobileOrder.amendment.version as read — a stale value is rejected."""
  expectedVersion: Int
  """The new quantities of the order lines."""
  lines: [MobileOrderLineQuantityInput!]!
  """The ID of the order."""
  orderId: ID!
}

"""Changes to the buyer's own profile."""
input UpdateMyProfileInput {
  """
  BUSINESS | INDIVIDUAL → the `Partner.type` COLUMN (mirrored onto `Partner.metadata.businessType`), so a buyer's change is visible to the seller console and vice versa. OMITTED leaves the stored value untouched (older builds send none).
  """
  businessType: String
  """The name of the buyer's company."""
  companyName: String
  """Department → the person's `Contact` rows. See `title`."""
  department: String
  "Email address."
  email: String!
  """
  Given name. Optional for older builds sending only `name`; takes precedence over splitting `name` when present.
  """
  firstName: String
  """Family name. See `firstName`."""
  lastName: String
  """The buyer's name."""
  name: String!
  """
  Mobile number in E.164 form (e.g. +97455551234) → User.phone. OMITTED leaves the stored number untouched; an explicit empty string CLEARS it. Nullable in the schema so older app builds that send no phone do not blank out a number the buyer already has.
  """
  phone: String
  """
  Job title → the person's `Contact` rows. Omitted leaves it untouched; '' clears it.
  """
  title: String
  """
  WhatsApp number in E.164 form → the person's WHATSAPP `Contact` channel row (there is no WhatsApp column on `User`). Same omitted-vs-empty rule as `phone`: OMITTED leaves it untouched, an explicit empty string CLEARS the channel.
  """
  whatsapp: String
}

"""Changes to the organization. Omitted fields stay as they are."""
input UpdateOrganizationInput {
  """The street address."""
  address: String
  """The city."""
  city: String
  """The country."""
  country: String
  """
  False to skip credit limit enforcement for this organization's sales and purchase order confirmation.
  """
  creditLimitEnabled: Boolean
  "ISO 4217 currency code."
  currency: String
  """The date format."""
  dateFormat: String
  "Email address."
  email: String
  """The organization's industry."""
  industry: String
  """The default language."""
  language: String
  """The latitude of the company address on the map."""
  latitude: Float
  """The longitude of the company address on the map."""
  longitude: Float
  """The name of the organization."""
  name: String
  """The password of the first admin user. It is write-only."""
  password: String
  "Phone number."
  phone: String
  """The postal code."""
  postalCode: String
  """The organization's company registration number."""
  registrationNumber: String
  """
  True to park customers created by non-admin users, such as sales reps, as pending until an admin activates them.
  """
  requireCustomerApproval: Boolean
  """The size of the organization."""
  size: String
  """The state or region."""
  state: String
  """The subdomain the organization is reached on."""
  subdomain: String
  """The organization's tax ID."""
  taxId: String
  """The time zone of the organization."""
  timezone: String
  """The organization's website."""
  website: String
}

"""Changes to a partner. Omitted fields stay as they are."""
input UpdatePartnerInput {
  """The partner's addresses. They replace the saved list."""
  addresses: [CreateAddressInput!]
  """
  The ID of the sales rep the customer is assigned to. Only admins can change it.
  """
  assignedSalesRepId: String
  """The partner code. Leave out to generate one."""
  code: String
  """The partner's contacts. They replace the saved list."""
  contacts: [CreateContactInput!]
  """The credit limit. 0 or less means unlimited."""
  creditLimit: Float
  """The balance."""
  currentBalance: Float
  """The partner's customer tier."""
  customerTier: String
  """What the partner is."""
  description: String
  """The standing discount, in percent."""
  discountPercent: Float
  """The name to show for the partner."""
  displayName: String
  """The ID of the partner to change."""
  id: ID!
  """The partner's industry."""
  industry: String
  """
  True when portal access is given separately, right after this create, so no login is made from the first email contact.
  """
  inviteSeparately: Boolean
  """The expected days from order to delivery."""
  leadTimeDays: Int
  """The legal name of the partner."""
  legalName: String
  """The partner's loyalty points."""
  loyaltyPoints: Int
  """The smallest order value."""
  minOrderValue: Float
  """The name of the partner."""
  name: String
  """Notes about the partner."""
  notes: String
  """The payment terms agreed with the partner."""
  paymentTerms: String
  """The currency of the partner's documents."""
  preferredCurrency: String
  """
  The language of documents sent to the partner. Leave out to use the organization's default.
  """
  preferredLanguage: String
  """A rating of the partner."""
  rating: Float
  """The partner's company registration number."""
  registrationNumber: String
  """The roles of the partner, such as customer or supplier."""
  roles: [PartnerRole!]
  """
  Which staff app the partner is created in, for example Admin Web or Sales App. It is shown in the pending approval queue.
  """
  source: String
  """The status of the partner."""
  status: PartnerStatus
  """Tags on the partner."""
  tags: [String!]
  """The customer's tax exemption. Customer partners only."""
  taxExemption: CustomerTaxExemptionInput
  """The partner's tax ID."""
  taxId: String
  """The kind of partner."""
  type: PartnerType
  """The partner's website."""
  website: String
}

"""Changes to a payment. Omitted fields stay as they are."""
input UpdatePaymentInput {
  """Payment amount, in currencyCode."""
  amount: Float
  """Cheque date, as an ISO 8601 date."""
  checkDate: String
  """Cheque number, for cheque payments."""
  checkNumber: String
  """ISO 4217 currency code of the payment."""
  currencyCode: String
  """
  Optimistic-concurrency check: the version this client read. Stale → typed VERSION_CONFLICT under COMMAND_CAS=enforce.
  """
  expectedVersion: Int
  """Notes about the payment."""
  notes: String
  """Date of the payment, as an ISO 8601 date."""
  paymentDate: String
  """How the payment was made."""
  paymentMethod: PaymentMethod
  """
  Your reference for the payment, such as a bank or transaction reference.
  """
  referenceNumber: String
}

"""Changes to a payment term. Omitted fields stay as they are."""
input UpdatePaymentTermInput {
  """Longer explanation of the term."""
  description: String
  """The ID of the payment term to change. Its code cannot be changed."""
  id: ID!
  """Whether the term can be chosen on new documents."""
  isActive: Boolean
  """Name shown when choosing the term."""
  label: String
  """Number of days from the invoice date until payment is due."""
  netDays: Int
  """Display order of the term in lists."""
  sortOrder: Int
}

"""Changes to the portal settings. Omitted fields stay as they are."""
input UpdatePortalConfigInput {
  """The accent colour."""
  accentColor: String
  """True when customers can order directly."""
  allowDirectOrders: Boolean
  """True when visitors can browse without signing in."""
  allowGuestBrowsing: Boolean
  """True when customers can request quotes."""
  allowQuoteRequests: Boolean
  """True when customers can register themselves."""
  allowSelfRegistration: Boolean
  """True when customer orders go through the buyer-side approval workflow."""
  approvalWorkflowEnabled: Boolean
  """The URL of the portal favicon."""
  faviconUrl: String
  """True when the portal is switched on."""
  isEnabled: Boolean
  """The URL of the portal logo."""
  logoUrl: String
  """The Play Store link behind the invite page's Get the app button."""
  mobileAndroidStoreUrl: String
  """The App Store link behind the invite page's Get the app button."""
  mobileIosStoreUrl: String
  """
  The image shown wherever a product, category or other catalog image is missing.
  """
  placeholderImageUrl: String
  """The name shown on the portal."""
  portalName: String
  """The main brand colour."""
  primaryColor: String
  """True when stock levels are shown."""
  showInventory: Boolean
  """True when prices are shown."""
  showPricing: Boolean
  """The support email address."""
  supportEmail: String
  """The support phone number."""
  supportPhone: String
  """The welcome message on the portal."""
  welcomeMessage: String
}

"""Changes to a product. Omitted fields stay as they are."""
input UpdateProductInput {
  """The ID of the base unit of measure."""
  baseUOMId: ID
  "The ID of the brand."
  brandId: ID
  """The IDs of the categories the product is in."""
  categoryIds: [ID!]
  """What the product is."""
  description: String
  """The ID of the product to change."""
  id: ID!
  """The URLs of the product images."""
  imageUrls: [String!]
  """The ID of the unit of measure stock is kept in."""
  inventoryUOMId: ID
  """True when the product is exempt from tax."""
  isTaxExempt: Boolean
  """The name of the product."""
  name: String
  """The ID of the main category."""
  primaryCategoryId: ID
  """
  The tax group used when buying the product, on purchase orders and supplier bills. An empty string clears it.
  """
  purchaseTaxGroupId: String
  """The ID of the unit of measure used for purchases."""
  purchaseUOMId: ID
  """The ID of the unit of measure used for sales."""
  salesUOMId: ID
  """The status of the product."""
  status: ProductStatus
  """Tags on the product."""
  tags: [String!]
  """Why the product is exempt from tax."""
  taxExemptReason: String
  "The ID of the tax group."
  taxGroupId: String
  """
  The IDs of the tax rates on the product, as one comma-separated string.
  """
  taxRateId: String
  """The variants of the product."""
  variants: [CreateProductVariantInput!]
}

"""Changes to a variant. Omitted fields stay as they are."""
input UpdateProductVariantInput {
  """The QR code of the variant."""
  QRCode: String
  """The variant's attributes, such as colour or size, as JSON."""
  attributes: JSON
  """The barcode of the variant."""
  barcode: String
  """The ID of the base unit of measure."""
  baseUOMId: ID
  """The cost of one unit."""
  cost: Float
  """The size of one unit, as JSON."""
  dimensions: JSON
  """The URL of the main image."""
  imageUrl: String
  """The URLs of the images."""
  imageUrls: [String!]
  """The ID of the unit of measure stock is kept in."""
  inventoryUOMId: ID
  "Whether the record is active."
  isActive: Boolean
  "Whether this is the default."
  isDefault: Boolean
  """The largest quantity that can be ordered."""
  maxOrderQuantity: Float
  """The page description for search engines."""
  metaDescription: String
  """The page title for search engines."""
  metaTitle: String
  """The smallest quantity that can be ordered."""
  minOrderQuantity: Float
  """The name of the variant."""
  name: String
  """Opening stock quantity"""
  openingStock: Float
  """Batch number for opening stock"""
  openingStockBatchNumber: String
  """Cost per unit for opening stock"""
  openingStockCost: Float
  """The list price. Must be greater than zero."""
  price: Float
  """The ID of the unit of measure used for purchases."""
  purchaseUOMId: ID
  """Pre-negotiated sale price"""
  salePrice: Float
  """The ID of the unit of measure used for sales."""
  salesUOMId: ID
  """The serial number of the variant."""
  serialNo: String
  """The SKU of the variant."""
  sku: String
  """Tags on the variant."""
  tags: [String!]
  """The price tiers, by quantity and customer tier."""
  variantPrices: [CreateVariantPriceInput!]
  """Warehouse ID for inventory updates"""
  warehouseId: ID
  """The weight of one unit."""
  weight: Float
}

"""Changes to the signed-in user's own profile."""
input UpdateProfileInput {
  """The address."""
  address: String
  """The URL of the picture."""
  avatar: String
  """A short bio."""
  bio: String
  """The city."""
  city: String
  """The country."""
  country: String
  "Email address."
  email: String
  """The first name."""
  firstName: String
  """The language."""
  language: String
  """The last name."""
  lastName: String
  """Where the user is based."""
  location: String
  "Phone number."
  phone: String
  """The postal code."""
  postalCode: String
  """The theme."""
  theme: String
  """The time zone."""
  timezone: String
}

"""Changes to a quote. Only the fields you send change."""
input UpdateQuoteInput {
  """Billing address shown on the quote."""
  billingAddress: String
  """
  Opt in to pricing a foreign-currency line with no price in the quote currency by converting its base price at exchangeRate. Without it such a line is refused. A price in the quote currency always wins.
  """
  convertMissingCurrencyPrices: Boolean
  """ISO 4217 currency code of the quote."""
  currency: String
  """
  Email address the quote is addressed to. It can differ from the customer's main email.
  """
  customerEmail: String
  """The ID of the customer the quote is for."""
  customerId: String
  """Customer mobile number shown on the quote."""
  customerMobile: String
  """Customer name shown on the quote."""
  customerName: String
  """Delivery instructions for this quote."""
  deliveryInstructions: String
  """Quote-level discount as an amount. Must not be negative."""
  discountAmount: Float
  """How the quote-level discount is read: PERCENTAGE or AMOUNT."""
  discountType: String
  """
  Quote-level discount, read as a percentage or an amount according to discountType. Must not be negative.
  """
  discountValue: Float
  """
  Exchange rate between the quote currency and the organization's base currency. Must be greater than zero.
  """
  exchangeRate: Float
  """
  Optimistic-concurrency check: the version this client read. Stale → typed VERSION_CONFLICT under COMMAND_CAS=enforce.
  """
  expectedVersion: Int
  """The ID of the quote to change."""
  id: ID!
  """Notes for your team only, not shown to the customer."""
  internalNotes: String
  """The quote lines."""
  items: [UpdateQuoteItemInput!]
  """Notes for the customer."""
  notes: String
  """The user who owns the quote."""
  ownership: DocumentOwnershipInput
  """Payment terms code. It must be a valid payment term code."""
  paymentTerms: String
  """Priority of the quote: LOW, NORMAL, HIGH or URGENT."""
  priority: String
  """
  The quote's date, as an ISO 8601 date. A date other than today needs the backdate permission and is recorded in the audit trail.
  """
  quoteDate: String
  """Reference shown on the quote, such as a customer enquiry number."""
  reference: String
  """Shipping address shown on the quote."""
  shippingAddress: String
  """Shipping cost for the quote. Must not be negative."""
  shippingCost: Float
  """
  Move the quote to this status. Only transitions the quote status rules allow are accepted.
  """
  status: String
  """Sum of the line values before quote-level discount, tax and shipping."""
  subtotal: Float
  """Total tax on the quote."""
  taxAmount: Float
  """Tax method for the whole quote: INCLUSIVE or EXCLUSIVE."""
  taxCalculationMethod: String
  """Quote-level tax rate."""
  taxRate: Float
  """Terms and conditions text for the quote."""
  terms: String
  """Total amount of the quote."""
  totalAmount: Float
  """Date the quote stops being valid, as an ISO 8601 date."""
  validUntil: String
  """The ID of the default warehouse for the quote."""
  warehouseId: String
}

"""One quote line in an update."""
input UpdateQuoteItemInput {
  """Free-text note shown on the quote line."""
  description: String
  """
  Line discount, read as a percentage or an amount according to discountType. Must not be negative; a percentage cannot exceed 100.
  """
  discount: Float!
  """Line discount as an amount. Must not be negative."""
  discountAmount: Float
  """How discount is read: PERCENTAGE or AMOUNT."""
  discountType: String!
  """The ID of the existing quote line. Omit for a new line."""
  id: ID
  """Why the price was overridden."""
  overrideReason: String
  """
  Set to true to keep a negotiated unitPrice instead of the catalogue price. The caller needs the quote price-override permission.
  """
  priceOverride: Boolean
  """The ID of the product being quoted."""
  productId: String!
  """Product name shown on the quote line."""
  productName: String!
  """SKU shown on the quote line."""
  productSku: String
  """
  Quantity quoted, in the unit given by uomId. Must be greater than zero.
  """
  quantity: Float!
  """Pre-negotiated sale price from variant"""
  salePrice: Float
  """Tax amount for the line."""
  taxAmount: Float!
  """Tax split by component, as JSON."""
  taxBreakdown: JSON
  """
  Whether the line price includes or excludes tax: INCLUSIVE or EXCLUSIVE.
  """
  taxCalculationMethod: String
  """Tax rate applied to the line."""
  taxRate: Float!
  """Total for the line."""
  totalPrice: Float
  """Price per unit in the quote currency. Must not be negative."""
  unitPrice: Float!
  """The ID of the unit of measure for the quantity."""
  uomId: String
  """Name of the unit of measure, shown on the line."""
  uomName: String
  """The ID of the product variant being quoted."""
  variantId: String!
  """The ID of the warehouse that supplies this line."""
  warehouseId: String
}

"""Changes to a region. Omitted fields stay as they are."""
input UpdateRegionInput {
  """The name of the city."""
  cityName: String
  """The region code."""
  code: String
  """The country code."""
  countryCode: String
  "Whether the record is active."
  isActive: Boolean
  """The name of the region."""
  name: String
  """The pattern postal codes follow."""
  postalCodePattern: String
  """The state code."""
  stateCode: String
  """The time zone of the region."""
  timezone: String
}

"""Changes to a role. Omitted fields stay as they are."""
input UpdateRoleInput {
  """What the role is for."""
  description: String
  """The name to show for the role."""
  displayName: String
  """The ID of the role."""
  id: ID!
  "Whether the record is active."
  isActive: Boolean
  """Extra information about the role, as JSON text."""
  metadata: String
  """The name of the role."""
  name: String
  """The rank of the role."""
  priority: Int
}

"""Changes to a SKU pattern. Omitted fields stay as they are."""
input UpdateSKUPatternInput {
  "The ID of the brand."
  brandId: String
  "The ID of the category."
  categoryId: String
  """What the pattern is for."""
  description: String
  """An example of a generated SKU."""
  example: String
  "Whether the record is active."
  isActive: Boolean
  """The name of the pattern."""
  name: String
  """The pattern, using placeholders such as {BRAND}-{CATEGORY}-{SEQ}."""
  pattern: String
  """Which pattern wins when several match. Defaults to 1."""
  priority: Int
  """How many digits the running number has. Defaults to 4."""
  sequenceLength: Int
}

"""
Input to edit a sales order. Fields left out are unchanged; which fields can change depends on the order's status.
"""
input UpdateSalesOrderInput {
  """Billing address for the order."""
  billingAddress: CreateSalesOrderAddressInput
  """
  Opt in to pricing a foreign-currency line with no price in the order currency by converting its base price. See CreateSalesOrderInput.
  """
  convertMissingCurrencyPrices: Boolean
  """
  ISO 4217 currency code of the order. It is fixed once the order leaves DRAFT.
  """
  currency: String
  """Customer email shown on the order."""
  customerEmail: String
  """Customer mobile number shown on the order."""
  customerMobile: String
  """Buyer-supplied PO number. Non-financial: still editable after DRAFT."""
  customerPoNumber: String
  """Delivery instructions for the order."""
  deliveryInstructions: String
  """Additional order-level discount as an amount. Must not be negative."""
  discountAmount: Float
  """
  Exchange rate between the order currency and the organization's base currency. Must be greater than zero.
  """
  exchangeRate: Float
  """
  Optimistic-concurrency check: the version this client read. Stale → typed VERSION_CONFLICT under COMMAND_CAS=enforce.
  """
  expectedVersion: Int
  """Notes for your team only, not shown to the customer."""
  internalNotes: String
  """
  The order lines. Lines can only be changed while the order is unpaid and not shipped or invoiced.
  """
  items: [CreateSalesOrderItemInput!]
  """Notes for the customer."""
  notes: String
  """
  Re-date the order, as an ISO 8601 date. Needs the backdate permission, like create.
  """
  orderDate: String
  """Payment terms code for the order."""
  paymentTerms: String
  """Date the order is promised for delivery."""
  promisedDate: DateTime
  """Reference shown on the order."""
  reference: String
  """Shipping address for the order."""
  shippingAddress: CreateSalesOrderAddressInput
  """Shipping charge for the order."""
  shippingAmount: Float
  """Shipping method for the order."""
  shippingMethod: String
  """
  Whether prices include or exclude tax: INCLUSIVE or EXCLUSIVE. It is fixed once the order leaves DRAFT.
  """
  taxCalculationMethod: String
  """The ID of the default warehouse for the order."""
  warehouseId: String
}

"""
Sets the organization-wide discount ceiling. It is enforced as a hard cap on any manual price.
"""
input UpdateSalesPolicyInput {
  """Maximum discount (%) any override may imply; 100 disables the ceiling"""
  maxDiscountPercent: Float!
}

"""Changes to the rules for sending marketing messages."""
input UpdateSendGovernorSettingsInput {
  """The most marketing messages one customer may get per day."""
  dailyCapPerPartner: Int
  """True when marketing messages may be sent at all."""
  marketingEnabled: Boolean
  """The hour the send window closes."""
  sendWindowCloseHour: Int
  """The hour the send window opens."""
  sendWindowOpenHour: Int
  """The most marketing messages one contact may get per week."""
  weeklyCapPerContact: Int
}

"""Changes to a tax group. Omitted fields stay as they are."""
input UpdateTaxGroupInput {
  """How the rates in the group combine."""
  calculationMethod: TaxCalculationMethod
  """The new code."""
  code: String
  """The new description."""
  description: String
  """The ID of the group to change."""
  id: ID!
  "Whether the record is active."
  isActive: Boolean
  """The new name."""
  name: String
  """The IDs of the tax rates in the group. They replace the saved list."""
  taxRateIds: [String!]
}

"""Changes to a tax rate. Omitted fields stay as they are."""
input UpdateTaxRateInput {
  """The product categories the tax applies to."""
  applicableProductCategories: [String!]
  """How the tax is worked out against the price."""
  calculationMethod: TaxCalculationMethod
  """The city the tax applies in."""
  city: String
  """The code of the tax rate."""
  code: String
  """The country the tax applies in."""
  country: String
  """What the tax rate is for."""
  description: String
  """The product categories the tax does not apply to."""
  exemptProductCategories: [String!]
  """The ID of the tax rate to change."""
  id: ID!
  "Whether the record is active."
  isActive: Boolean
  "Whether this is the default."
  isDefault: Boolean
  """The level the tax applies at: federal, state, county, city or custom."""
  jurisdiction: TaxJurisdiction
  """The largest amount the tax applies to."""
  maximumAmount: Float
  """The smallest amount the tax applies to."""
  minimumAmount: Float
  """The name of the tax rate."""
  name: String
  """The postal code the tax applies in."""
  postalCode: String
  """The rate, in percent."""
  rate: Float
  """The state or region the tax applies in."""
  state: String
  """The kind of tax."""
  type: TaxType
  """When the tax starts to apply."""
  validFrom: DateTime
  """When the tax stops applying."""
  validTo: DateTime
}

"""
Changes to the organization's localization after onboarding. Only the fiscal year month for now.
"""
input UpdateTenantLocalizationInput {
  """Calendar month (1 = January … 12 = December) the fiscal year begins in"""
  fiscalYearStart: Int!
}

"""
Input to set the address customer replies to document emails are routed to.
"""
input UpdateTenantReplyEmailInput {
  """Suffix for From name (default: "via Growmax")"""
  fromNameSuffix: String
  """Custom reply email address. Set to null to use quote owner email."""
  quoteReplyEmail: String
  """Enable/disable quote email sending"""
  quoteSendingEnabled: Boolean
}

"""Changes to a setting. Omitted fields stay as they are."""
input UpdateTenantSettingInput {
  """The group the setting is in."""
  category: SettingCategory
  """The data type of the value."""
  dataType: SettingDataType
  """What the setting does."""
  description: String
  """The ID of the setting."""
  id: String!
  "Whether the record is active."
  isActive: Boolean
  """The key of the setting."""
  key: String
  """A rule the value must follow."""
  validationRule: String
  """The value."""
  value: JSON
}

"""Changes to a time zone. Omitted fields stay as they are."""
input UpdateTimezoneInput {
  """The short name, for example GMT."""
  abbreviation: String
  """The IANA time zone code, for example Europe/London."""
  code: String
  """A description of the time zone."""
  description: String
  """When daylight saving time ends."""
  dstEnd: String
  """The offset during daylight saving time."""
  dstOffset: String
  """When daylight saving time starts."""
  dstStart: String
  """True when it observes daylight saving time."""
  dstSupported: Boolean
  "Whether the record is active."
  isActive: Boolean
  "Whether this is the default."
  isDefault: Boolean
  """The name of the time zone."""
  name: String
  """The offset from UTC."""
  offset: String
  """The regions it covers."""
  regions: [String!]
  """The position in lists, lowest first."""
  sortOrder: Int
}

"""Changes to a unit of measure. Only the fields you send change."""
input UpdateUOMInput {
  """
  Whether quantities in this unit may be fractional. Must be false for a COUNT unit.
  """
  allowFractional: Boolean
  """Colour code used to show the unit."""
  colorCode: String
  """The ID of the unit this unit combines with in compound quantities."""
  compoundWithUOMId: String
  """
  How many decimal places quantities in this unit show, from 0 to 6. Must be 0 for a COUNT unit.
  """
  decimalPlaces: Int
  """Free-text description of the unit."""
  description: String
  """Position of the unit in lists. Lower numbers come first."""
  displayOrder: Int
  """URL of the unit's icon image."""
  iconUrl: String
  """
  Set to false to deactivate the unit. The organization's default unit and the base unit of a product cannot be deactivated.
  """
  isActive: Boolean
  """The unit's name. At most 100 characters."""
  name: String
  """Plural form of the name, when it needs one."""
  pluralName: String
  """Symbol shown next to quantities in this unit. At most 20 characters."""
  symbol: String
}

"""Changes to a user. Omitted fields stay as they are."""
input UpdateUserInput {
  """The URL of the picture."""
  avatar: String
  "Email address."
  email: String
  """The first name."""
  firstName: String
  """The job title."""
  jobRole: String
  """The last name."""
  lastName: String
  "Phone number."
  phone: String
  """The role."""
  role: UserRole
  "The ID of the role."
  roleId: String
  """The status."""
  status: UserStatus
}

"""Changes to a user's preferences. Omitted fields stay as they are."""
input UpdateUserPreferencesInput {
  """The ID of the currency."""
  currencyId: String
  """The date format."""
  dateFormat: String
  """The ID of the language."""
  languageId: String
  """The number format."""
  numberFormat: String
  """The ID of the region."""
  regionId: String
  """The time format."""
  timeFormat: String
  """The time zone."""
  timezone: String
}

"""Changes to a relationship between two users."""
input UpdateUserRelationshipInput {
  """Whether this relationship is active"""
  isActive: Boolean
  """Optional notes about this relationship"""
  notes: String
}

"""Changes to a vendor product. Omitted fields stay as they are."""
input UpdateVendorProductInput {
  """The credit limit the vendor gives."""
  creditAmount: Float
  """The days of credit the vendor gives."""
  creditDays: Int
  "ISO 4217 currency code."
  currency: String
  """A rating of the vendor's delivery performance."""
  deliveryRating: Float
  """The ID of the vendor product to change."""
  id: ID!
  "Whether the record is active."
  isActive: Boolean
  """True when this is a preferred vendor for the product."""
  isPreferred: Boolean
  """The expected days from order to delivery."""
  leadTimeDays: Int
  """The largest quantity the vendor will supply per order."""
  maxOrderQuantity: Float
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The smallest quantity the vendor will supply per order."""
  minOrderQuantity: Float
  """Notes about the vendor product."""
  notes: String
  """Orders must be a multiple of this quantity."""
  orderMultiple: Float
  "The ID of the product."
  productId: String
  """A rating of the quality of the vendor's goods."""
  qualityRating: Float
  """The agreed standard cost of one unit."""
  standardCost: Float
  "The ID of the product variant."
  variantId: String
  """The brand the vendor sells the product under."""
  vendorBrand: String
  """The vendor's own name for the product."""
  vendorName: String
  """The ID of the vendor."""
  vendorPartnerId: String
  """The vendor's own code for the product."""
  vendorSku: String
}

"""Changes to a warehouse. Omitted fields stay as they are."""
input UpdateWarehouseInput {
  """
  The address as JSON: street1, street2, city, state, country, postalCode, and optionally latitude and longitude.
  """
  address: JSON
  """The storage capacity of the warehouse."""
  capacity: Int
  """The warehouse code, unique within the organization."""
  code: String
  """The contact email address."""
  contactEmail: String
  """The contact phone number."""
  contactPhone: String
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """The warehouse name."""
  name: String
  """Whether the warehouse is in use."""
  status: WarehouseStatus
  """
  The tax registration number of this location. When blank, the organization's number is used on the documents the warehouse issues.
  """
  taxRegistrationNumber: String
  """The kind of warehouse, such as main, branch or distribution."""
  type: String
}

"""Changes the setup of one WhatsApp trigger."""
input UpdateWhatsAppTriggerInput {
  """True to switch the trigger on."""
  enabled: Boolean!
  """The language code of the template."""
  languageCode: String
  """The name of the template to send."""
  templateName: String
  """The key of the trigger."""
  triggerKey: String!
}

"""The unit and file details for an icon upload."""
input UploadUOMImageInput {
  """The image type: image/jpeg, image/png, image/gif or image/webp."""
  contentType: String!
  """The image file's name."""
  filename: String!
  """The ID of the unit the image is for."""
  uomId: String!
}

"""
The pre-signed upload URL for a unit's icon, the URL the image will be served from, and its storage key.
"""
type UploadUOMImageResult {
  """The storage key of the uploaded image."""
  key: String!
  """The URL the image is served from after upload."""
  publicUrl: String!
  """The pre-signed URL to upload the image to."""
  uploadUrl: String!
}

"""Saves a delivery partner. Leave out the ID to add a new partner."""
input UpsertDeliveryPartnerConfigInput {
  """
  The credentials to store. For a secret field, leave it out or send an empty value to keep the stored one.
  """
  credentials: [DeliveryPartnerKeyValueInput!]
  """The name to show for the partner."""
  displayName: String
  """The provider environment the credentials belong to."""
  environment: DeliveryEnvironment!
  """The ID of the partner to change. Leave out to add a new one."""
  id: ID
  """The provider key."""
  providerKey: String!
  """The settings to store."""
  settings: [DeliveryPartnerKeyValueInput!]
  """The position of the partner in lists, lowest first."""
  sortOrder: Int
  """
  Legacy, stored but ignored: every enabled partner is offered at checkout (2026-10-13).
  """
  useForCheckout: Boolean
}

"""Saves a rep's plan for one day."""
input UpsertJourneyPlanInput {
  """Notes on the plan."""
  notes: String
  """The day of the plan."""
  planDate: DateTime!
  """The ID of the rep."""
  salesRepId: String!
  """The stops of the day. They replace the saved list."""
  visits: [JourneyPlanVisitInput!]!
}

"""Saves the organization's setup for a payment provider."""
input UpsertPaymentGatewayConfigInput {
  """
  Credentials as key and value pairs. For secret fields, omit or send an empty value to keep the existing one.
  """
  credentials: [CredentialValueInput!]!
  """The payment methods to offer through this gateway."""
  enabledMethods: [String!]
  """The provider environment the credentials belong to."""
  environment: PaymentGatewayEnvironment!
  """The payment provider."""
  provider: PaymentGatewayProvider!
}

"""Saves the organization's WhatsApp setup."""
input UpsertWhatsAppConfigInput {
  """
  The provider API key. Leave out or send empty to keep the stored key. It is write-only.
  """
  apiKey: String
  """
  The provider channel to send on, for respond.io. Leave out to keep the stored one.
  """
  channelId: String
  """The country code added to phone numbers that have none."""
  defaultCountryCode: String
  """Which provider's setup to write. Leave out for Interakt."""
  provider: WhatsAppProvider
}

"""A user of the organization."""
type User {
  """The address."""
  address: String
  """Every permission the user has, from roles and direct grants."""
  allPermissions: [String!]
  """The URL of the picture."""
  avatar: String
  """A short bio."""
  bio: String
  """The city."""
  city: String
  """The country."""
  country: String
  "When the record was created."
  createdAt: DateTime!
  """The permissions granted to the user directly."""
  directPermissions: [Permission!]
  "Email address."
  email: String!
  """The first name."""
  firstName: String!
  """
  True when the account has a password to change. False means the user signs in only by one-time code or single sign on, and can set one.
  """
  hasPassword: Boolean!
  "The unique ID of this record."
  id: ID!
  """The job title."""
  jobRole: String
  """The language."""
  language: String
  """When the user last signed in."""
  lastLogin: DateTime
  """When the user last signed in."""
  lastLoginAt: DateTime
  """The last name."""
  lastName: String!
  """Where the user is based."""
  location: String
  """True when the user must change their password at the next sign in."""
  mustChangePassword: Boolean!
  """The full name."""
  name: String!
  """The organization the user belongs to."""
  organization: Organization
  "The ID of the organization the record belongs to."
  organizationId: String!
  """When the password was last changed."""
  passwordChangedAt: DateTime!
  """
  The permissions the server enforces for the user, from their roles and direct grants.
  """
  permissions: [String!]!
  "Phone number."
  phone: String
  """The postal code."""
  postalCode: String
  """The role."""
  role: UserRole!
  """The roles the user is in."""
  roles: [Role!]
  """The status."""
  status: UserStatus!
  """The theme."""
  theme: String
  """The time zone."""
  timezone: String
  """True when two-factor sign in is on."""
  twoFactorEnabled: Boolean!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""How active users are."""
type UserActivity {
  """How many users were active."""
  activeUsers: Int!
  """Users and logins over time."""
  historicalData: [UserActivityHistorical!]
  """How many logins there were."""
  loginActivity: Int!
  """How many users registered."""
  newRegistrations: Int!
}

"""User activity for one period."""
type UserActivityHistorical {
  """How many logins there were."""
  logins: Int!
  """The period."""
  period: String!
  """How many users were active."""
  users: Int!
}

"""Filters for the user list."""
input UserFilterInput {
  """Filter on when the record was created."""
  createdAt: DateFilter
  """Filter on when the record was deleted."""
  deletedAt: DateFilter
  """Filter on the email address."""
  email: StringFilter
  """Filter on the first name."""
  firstName: StringFilter
  """Filter on whether the user has a picture."""
  hasAvatar: BooleanFilter
  """Filter on the ID."""
  id: StringFilter
  """Filter on the last sign in."""
  lastLoginAt: DateFilter
  """Filter on the last name."""
  lastName: StringFilter
  """Filter on the phone number."""
  phone: StringFilter
  """Filter on the role."""
  role: StringFilter
  """Global search across multiple fields"""
  search: String
  """Filter on the status."""
  status: StringFilter
  """Filter on when the record was last changed."""
  updatedAt: DateFilter
}

"""Filters for the user list."""
input UserFilters {
  """
  Only users who effectively have this permission, through an active role or a direct grant. For pickers that show staff by capability.
  """
  hasPermission: String
  """Only users with this role."""
  role: String
  "Text to search for."
  search: String
  """Only users with this status."""
  status: String
}

"""
An in-app notification for a staff user. Buyer notifications are a separate type.
"""
type UserNotification {
  """The text."""
  body: String!
  "When the record was created."
  createdAt: DateTime!
  """The ID of that record."""
  entityId: String
  """
  The kind of record the notification links to, for example SALES_ORDER or INVOICE.
  """
  entityType: String
  "The unique ID of this record."
  id: ID!
  "Additional data attached to the record, as JSON."
  metadata: JSON
  """When it was read. Empty means unread, which drives the bell badge."""
  readAt: DateTime
  """The title."""
  title: String!
  """
  What the notification is about, for example ORDER_STATUS, COLLECTION_REMINDER or SYSTEM.
  """
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
}

"""A page of notifications."""
type UserNotificationPage {
  """The notifications on this page."""
  items: [UserNotification!]!
  """An opaque cursor to pass for the next page. Empty on the last page."""
  nextCursor: String
}

"""An organization a person belongs to."""
type UserOrganizationInfo {
  "When the record was created."
  createdAt: DateTime!
  """The URL of the organization logo."""
  logoUrl: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The name of the organization."""
  organizationName: String!
  """The person's role in it."""
  role: String!
  """The subdomain of the organization."""
  subdomain: String!
}

"""A user's preferences."""
type UserPreference {
  "When the record was created."
  createdAt: DateTime!
  """The ID of the currency."""
  currencyId: String
  """The date format."""
  dateFormat: String
  "The unique ID of this record."
  id: ID!
  """The language."""
  language: Language
  """The ID of the language."""
  languageId: String
  """The number format."""
  numberFormat: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The ID of the region."""
  regionId: String
  """The time format."""
  timeFormat: String
  """The time zone."""
  timezone: String
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user."
  userId: String!
}

"""A relationship between two users, such as who reports to whom."""
type UserRelationship {
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """Notes about the relationship."""
  notes: String
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The supervisor or other related user."""
  relatedUser: User
  """The ID of the related user."""
  relatedUserId: String!
  """The kind of relationship."""
  relationshipType: UserRelationshipType!
  "When the record was last changed."
  updatedAt: DateTime!
  """The subordinate."""
  user: User
  "The ID of the user."
  userId: String!
}

"""A user's relationships in both directions."""
type UserRelationshipSummary {
  """Relationships where this user is the subordinate (their supervisors)"""
  subordinateOf: [UserRelationship!]!
  """Relationships where this user is the supervisor (their subordinates)"""
  supervisorOf: [UserRelationship!]!
}

"""Type of relationship between users in the organization hierarchy"""
enum UserRelationshipType {
  """A secondary reporting line."""
  DOTTED_LINE
  """A mentor of the user."""
  MENTOR
  """The user's direct manager."""
  REPORTS_TO
  """The lead of the user's territory."""
  TERRITORY_LEAD
}

"""
A user's role: SUPER_ADMIN, ADMIN, OWNER, MANAGER, SALES_REP, WAREHOUSE_STAFF, VIEWER, or a customer role CUSTOMER_ADMIN, CUSTOMER_BUYER or CUSTOMER_VIEWER.
"""
enum UserRole {
  """Manages the organization's settings and users."""
  ADMIN
  """Manages a customer company's account and team."""
  CUSTOMER_ADMIN
  """Places orders for a customer company."""
  CUSTOMER_BUYER
  """Views a customer company's orders only."""
  CUSTOMER_VIEWER
  """Manages a team."""
  MANAGER
  """Owns the organization."""
  OWNER
  """Sells to customers."""
  SALES_REP
  """A platform administrator."""
  SUPER_ADMIN
  """Can view and cannot change data."""
  VIEWER
  """Works in a warehouse."""
  WAREHOUSE_STAFF
}

"""User settings."""
input UserSettingsInput {
  """True to allow one user to be signed in more than once."""
  allowMultipleLogins: Boolean
  """The date format."""
  dateFormat: String
  """The default currency."""
  defaultCurrency: String
  """The default language."""
  defaultLanguage: String
  """The default time zone."""
  defaultTimezone: String
  """True to send notifications."""
  enableNotifications: Boolean
  """The size of profile pictures."""
  profileImageSize: String
  """The time format."""
  timeFormat: String
}

"""The status of a user: ACTIVE, INACTIVE or SUSPENDED."""
enum UserStatus {
  """Can sign in."""
  ACTIVE
  """Switched off."""
  INACTIVE
  """Blocked from signing in."""
  SUSPENDED
}

"""Checks an integration's configuration."""
input ValidateIntegrationInput {
  """The ID of the integration setting."""
  id: String!
}

"""Figures about the variants."""
type VariantAnalytics {
  """How the variants spread."""
  distribution: VariantDistribution!
  """Variants worth attention."""
  insights: VariantInsights!
  """Headline counts."""
  summary: VariantSummary!
}

"""How the variants spread."""
type VariantDistribution {
  """By attribute value."""
  byAttributes: [AttributeDistribution!]!
  """By product."""
  byProduct: [ProductVariantCount!]!
}

"""Filters for the variant list."""
input VariantFilterInput {
  """Only variants with these attribute values, as JSON."""
  attributes: JSON
  "The ID of the brand."
  brandId: ID
  """Only variants of products in these categories."""
  categoryIds: [ID!]
  """Only variants that have stock."""
  hasStock: Boolean
  "Whether the record is active."
  isActive: Boolean
  """Only variants in this price range."""
  priceRange: PriceRangeInput
  "The ID of the product."
  productId: ID
  "Text to search for."
  search: String
  "Number of records to skip. Send with take to page through results."
  skip: Int = 0
  "Number of records to return."
  take: Int = 50000
}

"""Variants worth attention."""
type VariantInsights {
  """Variants that are low on stock."""
  lowStockVariants: [ProductVariant!]!
  """Variants that sell the most."""
  topSellingVariants: [ProductVariant!]!
}

"""A price tier on a variant."""
type VariantPrice {
  """The cost of one unit in the tier."""
  cost: Float
  "When the record was created."
  createdAt: DateTime!
  """
  ISO currency this row is denominated in; null = org base currency. Per-currency ladders are entered as-is, never derived by conversion (Rule A).
  """
  currency: String
  """The customer tiers the price is for."""
  customerTierIds: [String!]!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The discount in percent."""
  discountPercent: Float!
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The largest quantity the tier applies to."""
  maxQuantity: Float
  """The smallest quantity the tier applies to."""
  minQuantity: Float!
  """The name of the tier."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The price in the tier."""
  price: Float!
  """
  UOM the tier qty/price are denominated in; null = base units (legacy ladder, ×cf).
  """
  uomId: String
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """When the tier starts to apply."""
  validFrom: DateTime
  """When the tier stops applying."""
  validTo: DateTime
  """The variant the tier is on."""
  variant: ProductVariant
  "The ID of the product variant."
  variantId: ID!
}

"""A page of variant search results."""
type VariantSearchResult {
  """How many variants match."""
  total: Int!
  """The variants found."""
  variants: [ProductVariant!]!
}

"""Headline variant counts."""
type VariantSummary {
  """How many are active."""
  activeVariants: Int!
  """The average number of variants per product."""
  averageVariantsPerProduct: Int!
  """How many are inactive."""
  inactiveVariants: Int!
  """How many variants there are."""
  totalVariants: Int!
}

"""
How much of a variant one warehouse holds and how much of it is free. Quantities are in the variant's base unit.
"""
type VariantWarehouseStock {
  """The quantity free to allocate, never below zero."""
  availableQuantity: Float!
  """The quantity on hand, reservations included."""
  onHandQuantity: Float!
  """The quantity held by confirmed orders."""
  reservedQuantity: Float!
  """
  False when the variant has no stock row anywhere in the organization, meaning its stock is not tracked.
  """
  tracked: Boolean!
  "The ID of the product variant."
  variantId: ID!
  """The code of the warehouse."""
  warehouseCode: String
  "The ID of the warehouse."
  warehouseId: ID!
  """The name of the warehouse."""
  warehouseName: String!
}

"""The vendor side of a partner: terms, contract, ratings and risk."""
type VendorAccount {
  """True when the contract renews by itself."""
  autoRenewal: Boolean!
  """The average value of a purchase."""
  averagePurchaseValue: Float!
  """The vendor's business category."""
  businessCategory: String
  """The vendor's capacity."""
  capacity: String
  """The vendor's certifications."""
  certifications: [String!]!
  """When the contract ends."""
  contractEndDate: DateTime
  """When the contract starts."""
  contractStartDate: DateTime
  """The kind of contract."""
  contractType: String
  """The value of the contract."""
  contractValue: Float
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """The delivery rating."""
  deliveryRating: Float
  """How reliably the vendor delivers on time."""
  deliveryReliability: Float
  """The days within which paying early earns a discount."""
  earlyPaymentDays: Int!
  """The discount for paying early, in percent."""
  earlyPaymentDiscount: Float!
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  """The vendor's insurance cover."""
  insuranceCoverage: Float
  """The languages the vendor works in."""
  languages: [String!]!
  """The date of the last evaluation."""
  lastEvaluationDate: DateTime
  """The date of the last purchase."""
  lastPurchaseDate: DateTime
  """The expected days from order to delivery."""
  leadTimeDays: Int!
  """The largest order value."""
  maximumOrderValue: Float
  """The smallest order value."""
  minimumOrderValue: Float
  """How the risk is reduced."""
  mitigation: String
  """The date of the next evaluation."""
  nextEvaluationDate: DateTime
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The overall rating."""
  overallRating: Float
  "The ID of the partner."
  partnerId: String!
  """The payment terms the vendor gives."""
  paymentTerms: String!
  """The performance rating."""
  performanceRating: Float
  """The product categories the vendor supplies."""
  productCategories: [String!]!
  """The quality rating."""
  qualityRating: Float
  """The quality score."""
  qualityScore: Float
  """The factors behind the risk."""
  riskFactors: [String!]!
  """The level of risk the vendor carries."""
  riskLevel: String
  """The areas the vendor serves."""
  serviceAreas: [String!]!
  """The service rating."""
  serviceRating: Float
  """The technology the vendor uses."""
  technology: [String!]!
  """The total value of purchases."""
  totalPurchaseValue: Float!
  """How many purchases there have been."""
  totalPurchases: Int!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The vendor code."""
  vendorCode: String!
  """The kind of vendor."""
  vendorType: String
  """The volume discount tier."""
  volumeDiscountTier: String
}

"""The vendor on a vendor product."""
type VendorPartner {
  """The vendor code."""
  code: String!
  """The name to show for the vendor."""
  displayName: String
  "The unique ID of this record."
  id: ID!
  """The vendor name."""
  name: String!
}

"""
A product variant a vendor supplies, with the vendor's own code, terms, costs and delivery record. Costs and lead times are updated from goods receipts.
"""
type VendorProduct {
  """The average cost of one unit across receipts."""
  averageCost: Float
  """The average lead time in days across receipts."""
  averageLeadTime: Float
  """The average value of a purchase."""
  averageOrderValue: Float
  "When the record was created."
  createdAt: DateTime!
  """The credit limit the vendor gives."""
  creditAmount: Float!
  """The days of credit the vendor gives."""
  creditDays: Int!
  "ISO 4217 currency code."
  currency: String!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """A rating of the vendor's delivery performance."""
  deliveryRating: Float
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """True when this is a preferred vendor for the product."""
  isPreferred: Boolean!
  """The cost of one unit on the last receipt."""
  lastCost: Float
  """The unit cost on the last receipt."""
  lastGrnCost: Float
  """The date of the last receipt."""
  lastGrnDate: DateTime
  """The lead time in days on the last receipt."""
  lastGrnLeadTime: Int
  """The quantity on the last receipt."""
  lastGrnQuantity: Float
  """The date of the last purchase."""
  lastPurchaseDate: DateTime
  """The price of one unit on the last purchase."""
  lastPurchasePrice: Float
  """The quantity on the last purchase."""
  lastPurchaseQty: Float
  """The expected days from order to delivery."""
  leadTimeDays: Int!
  """The largest quantity the vendor will supply per order."""
  maxOrderQuantity: Float
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """The smallest quantity the vendor will supply per order."""
  minOrderQuantity: Float!
  """Notes about the vendor product."""
  notes: String
  """How many deliveries arrived on time."""
  onTimeDeliveries: Int!
  """The share of deliveries that arrived on time, in percent."""
  onTimeDeliveryPercentage: Float
  """Orders must be a multiple of this quantity."""
  orderMultiple: Float!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """The product."""
  product: VendorProductInfo
  "The ID of the product."
  productId: String!
  """A rating of the quality of the vendor's goods."""
  qualityRating: Float
  """The agreed standard cost of one unit."""
  standardCost: Float
  """The total cost of everything received."""
  totalCostValue: Float!
  """How many deliveries there have been."""
  totalDeliveries: Int!
  """How many receipts there have been."""
  totalGrnCount: Int!
  """The lead time in days added up across receipts."""
  totalLeadTime: Int!
  """The total value of purchases."""
  totalPurchaseValue: Float!
  """How many purchases there have been."""
  totalPurchases: Int!
  """The total quantity received."""
  totalQuantity: Float!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The product variant."""
  variant: VendorProductVariant
  "The ID of the product variant."
  variantId: String!
  """The vendor."""
  vendor: VendorPartner
  """The brand the vendor sells the product under."""
  vendorBrand: String
  """The vendor's own name for the product."""
  vendorName: String
  """The ID of the vendor."""
  vendorPartnerId: String!
  """The vendor's own code for the product."""
  vendorSku: String!
}

"""Filters for the vendor product list."""
input VendorProductFilterInput {
  "ISO 4217 currency code."
  currency: String
  "Whether the record is active."
  isActive: Boolean
  """Only preferred vendor products, or not."""
  isPreferred: Boolean
  """Only products costing at most this."""
  maxCost: Float
  """Only products delivered within this many days."""
  maxLeadTimeDays: Int
  """Only products costing at least this."""
  minCost: Float
  """Only products rated at least this for quality."""
  minQualityRating: Float
  "The ID of the product."
  productId: String
  "Text to search for."
  search: String
  "The ID of the product variant."
  variantId: String
  """Only products from this vendor."""
  vendorPartnerId: String
  """Only the product with this vendor code."""
  vendorSku: String
}

"""The product on a vendor product."""
type VendorProductInfo {
  """The product barcode."""
  barcode: String
  "The unique ID of this record."
  id: ID!
  """The product name."""
  name: String!
  """The product SKU."""
  sku: String!
}

"""The variant on a vendor product."""
type VendorProductVariant {
  """The variant barcode."""
  barcode: String
  "The unique ID of this record."
  id: ID!
  """The variant name. Empty when the variant has only a SKU."""
  name: String
  """The variant SKU."""
  sku: String!
}

"""Checks a one-time code to sign in."""
input VerifyCustomerOtpInput {
  """The one-time code."""
  code: String!
  "Email address."
  email: String!
  """The subdomain of the organization the customer signs in to."""
  subdomain: String
}

"""Checks the one-time code for changing the email address."""
input VerifyEmailChangeOtpInput {
  """The one-time code."""
  code: String!
  """The NEW address the code was sent to."""
  email: String!
}

"""Checks the one-time code to sign in."""
input VerifyEmailOtpInput {
  """The one-time code."""
  code: String!
  "Email address."
  email: String!
  """
  ARC org subdomain this white-label build is pinned to (Constants.expoConfig.extra.orgSubdomain). MUST match the value sent to requestEmailOtp so the OTP key resolves. Optional only for backward-compat / dev fallback (MOBILE_BUYER_ORG_ID).
  """
  subdomain: String
}

"""
Step 2 of signing up: checks the emailed code and returns a short-lived verification token.
"""
input VerifyRegistrationOtpInput {
  "Email address."
  email: String!
  """The one-time code."""
  otp: String!
  """The ID returned when the code was requested."""
  requestId: String!
}

"""The result of step 2 of signing up."""
type VerifyRegistrationOtpResponse {
  """Seconds until the verification token expires"""
  expiresIn: Int
  """
  Short-lived token proving the email was verified; pass to registerWithOtp
  """
  verificationToken: String
  """True when the code was correct."""
  verified: Boolean!
}

"""Finishes a sign in with a two-factor code."""
input VerifyTwoFactorInput {
  """
  The single-use challenge returned by login when it said a two-factor code was required.
  """
  tempToken: String!
  """The code from the authenticator app, or a backup code."""
  token: String!
  "The ID of the user."
  userId: String!
}

"""A planned or unplanned visit to a customer."""
type Visit {
  """The check-ins of the visit."""
  checkIns: [VisitCheckIn!]!
  """When the visit was completed, as the rep's device reported it."""
  completedAt: DateTime
  "When the record was created."
  createdAt: DateTime!
  """True when an unread message from the office is waiting on this stop."""
  hasUnreadMessage: Boolean!
  "The unique ID of this record."
  id: ID!
  """The ID of the day plan. Empty for an unplanned visit the rep created."""
  journeyPlanId: String
  """
  True when the route generator could not find the customer's address coordinates. The stop was still assigned to a day.
  """
  locationMissing: Boolean!
  """Why no order was taken."""
  noOrderReason: String
  """Notes about the visit."""
  notes: String
  """How the visit ended."""
  outcome: VisitOutcome
  """
  True when the customer has an address or map pin the stop can be routed to.
  """
  partnerHasLocation: Boolean!
  "The ID of the partner."
  partnerId: String!
  """The latitude of the customer's address."""
  partnerLatitude: Float
  """The longitude of the customer's address."""
  partnerLongitude: Float
  """The name of the customer."""
  partnerName: String
  """The ID of the rep."""
  salesRepId: String!
  """The position of the stop in the day."""
  sequence: Int!
  """The status of the visit."""
  status: VisitStatus!
  "When the record was last changed."
  updatedAt: DateTime!
  """The day of the visit."""
  visitDate: DateTime!
}

"""A check-in at a visit."""
type VisitCheckIn {
  """When the rep checked in."""
  checkInAt: DateTime!
  """When the rep checked out."""
  checkOutAt: DateTime
  """The latitude where the rep checked out."""
  checkOutLatitude: Float
  """The longitude where the rep checked out."""
  checkOutLongitude: Float
  "When the record was created."
  createdAt: DateTime!
  "The unique ID of this record."
  id: ID!
  """The latitude where the rep checked in."""
  latitude: Float
  """The longitude where the rep checked in."""
  longitude: Float
  """The ID of the visit."""
  visitId: String!
}

"""Business outcome recorded when a visit is completed."""
enum VisitOutcome {
  """The visit ended without an order."""
  NO_ORDER
  """An order was placed during the visit."""
  ORDER_PLACED
}

"""Lifecycle state of a field-sales visit."""
enum VisitStatus {
  """Cancelled."""
  CANCELLED
  """The rep has arrived."""
  CHECKED_IN
  """Done."""
  COMPLETED
  """Planned and not started."""
  PLANNED
  """Left out of the day's route."""
  SKIPPED
}

"""Voids a payment."""
input VoidPaymentInput {
  """
  The version of the payment you last read. The change is refused if someone else changed it since.
  """
  expectedVersion: Int
  """The ID of the payment to void."""
  paymentId: ID!
  """Why the payment is being voided."""
  reason: String
}

"""A location where stock is held."""
type Warehouse {
  """The address of the warehouse."""
  address: WarehouseAddress
  """The storage capacity of the warehouse."""
  capacity: Int
  """The warehouse code, unique within the organization."""
  code: String!
  """The contact email address."""
  contactEmail: String
  """The contact phone number."""
  contactPhone: String
  "When the record was created."
  createdAt: DateTime!
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  "The ID of the user who created the record."
  enteredBy: String!
  "The unique ID of this record."
  id: ID!
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """The warehouse name."""
  name: String!
  "The ID of the organization the record belongs to."
  organizationId: String!
  """Whether the warehouse is in use."""
  status: WarehouseStatus!
  """
  The tax registration number of this location. When blank, the organization's number is used on the documents the warehouse issues.
  """
  taxRegistrationNumber: String
  """The kind of warehouse, such as main, branch or distribution."""
  type: String!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The zones inside the warehouse."""
  zones: [Zone!]
}

"""The address of a warehouse."""
type WarehouseAddress {
  """The city."""
  city: String
  """The country."""
  country: String
  """The latitude of the warehouse on the map."""
  latitude: Float
  """The longitude of the warehouse on the map."""
  longitude: Float
  """The postal code."""
  postalCode: String
  """The state or region."""
  state: String
  """The first line of the street address."""
  street1: String
  """The second line of the street address."""
  street2: String
}

"""Filters for the warehouse list."""
input WarehouseFilterInput {
  "Text to search for."
  search: String
  """Only warehouses in one of these statuses."""
  status: [WarehouseStatus!]
  """Only warehouses of this kind."""
  type: String
}

"""Status of the warehouse"""
enum WarehouseStatus {
  """In use."""
  ACTIVE
  """Not in use."""
  INACTIVE
  """Closed for maintenance."""
  MAINTENANCE
}

"""How full one warehouse is."""
type WarehouseUtilization {
  """The storage capacity."""
  capacity: Int!
  """The stock held."""
  currentStock: Int!
  """How much of the capacity is in use, in percent."""
  utilization: Float!
  "The ID of the warehouse."
  warehouseId: String!
  """The name of the warehouse."""
  warehouseName: String!
}

"""The value of stock in one warehouse."""
type WarehouseValuation {
  """How many units are held."""
  units: Float!
  """The value of the stock."""
  value: Float!
  "The ID of the warehouse."
  warehouseId: ID!
  """The name of the warehouse."""
  warehouseName: String!
}

"""One line of a warranty return."""
input WarrantyReturnItemInput {
  """The defects claimed."""
  defects: [String!]!
  "The ID of the product."
  productId: String!
  """True when the unit needs repair."""
  repairRequired: Boolean!
  """The serial number of the unit."""
  serialNumber: String!
  "The ID of the product variant."
  variantId: String!
}

"""One attempt to deliver an event to a webhook."""
type WebhookDelivery {
  """How many attempts were made."""
  attempts: Int!
  "When the record was created."
  createdAt: DateTime!
  """When it was delivered."""
  deliveredAt: DateTime
  """The ID of the endpoint."""
  endpointId: String!
  """The kind of event."""
  eventType: String!
  "The unique ID of this record."
  id: ID!
  """When the last attempt was made."""
  lastAttemptAt: DateTime
  """The error from the last attempt."""
  lastError: String
  """The HTTP status the endpoint answered with."""
  responseStatus: Int
  """PENDING, SUCCEEDED or FAILED."""
  status: String!
}

"""Filters for the webhook delivery log."""
input WebhookDeliveryFilterInput {
  """Only deliveries to this endpoint."""
  endpointId: String
  "Maximum number of records to return."
  limit: Int
  "Number of records to skip before the first one returned."
  offset: Int
  """Only deliveries in this status."""
  status: String
}

"""
A webhook endpoint of the organization. The signing secret is never a field here.
"""
type WebhookEndpoint {
  "When the record was created."
  createdAt: DateTime!
  """The kinds of event sent to it."""
  eventTypes: [String!]!
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  """The name of the endpoint."""
  name: String!
  """
  The last four characters of the secret, to identify it without revealing it.
  """
  secretHint: String!
  "When the record was last changed."
  updatedAt: DateTime!
  """The address events are sent to."""
  url: String!
}

"""A webhook endpoint to save."""
input WebhookEndpointInput {
  """The kinds of event to send."""
  eventTypes: [String!]!
  "Whether the record is active."
  isActive: Boolean
  """The name of the endpoint."""
  name: String!
  """The address to send events to."""
  url: String!
}

"""
A webhook endpoint with its signing secret. It is returned only when the endpoint is created or its secret is rotated, and cannot be read again.
"""
type WebhookEndpointWithSecret {
  """The endpoint."""
  endpoint: WebhookEndpoint!
  """The signing secret. It is shown once."""
  secret: String!
}

"""Webhook settings."""
input WebhookSettingsInput {
  """How long to wait before sending a batch."""
  batchDelay: String
  """How many events go in a batch."""
  batchSize: String
  """True to send events in batches."""
  enableBatching: Boolean
  """True to log webhook deliveries."""
  enableLogging: Boolean
  """True to limit how fast webhooks are sent."""
  enableRateLimiting: Boolean
  """True to sign webhook requests."""
  enableSigning: Boolean
  """True to switch webhooks on."""
  enableWebhooks: Boolean
  """How many days the log is kept."""
  logRetentionDays: String
  """How many times a failed webhook is retried."""
  maxRetries: String
  """The most webhooks sent per minute."""
  rateLimitPerMinute: String
  """How long to wait between retries."""
  retryDelay: String
  """How long to wait for an answer."""
  timeout: String
}

"""A WhatsApp channel in the provider account."""
type WhatsAppChannelGql {
  "The unique ID of this record."
  id: String!
  """The name of the channel."""
  name: String!
  """Where the channel comes from."""
  source: String!
}

"""The channels fetched from the provider."""
type WhatsAppChannelsResultGql {
  """The channels."""
  channels: [WhatsAppChannelGql!]!
  """Why it failed, if it did."""
  detail: String
  """True when the channels were fetched."""
  ok: Boolean!
}

"""
The organization's WhatsApp setup. The API key is never returned in full.
"""
type WhatsAppConfigGql {
  """The last four characters of the API key."""
  apiKeyLast4: String
  """What the provider supports."""
  capabilities: WhatsAppProviderCapabilitiesGql!
  """The ID of the channel messages are sent on."""
  channelId: String
  """The name of that channel."""
  channelName: String
  """The country code added to phone numbers that have none."""
  defaultCountryCode: String
  """The name of the setup."""
  displayName: String!
  """True when an API key is stored."""
  hasApiKey: Boolean!
  "The unique ID of this record."
  id: ID!
  """True when WhatsApp sending is switched on."""
  isEnabled: Boolean!
  """The provider."""
  provider: String!
  """The setup of each trigger."""
  triggers: [WhatsAppTriggerConfigGql!]!
  "When the record was last changed."
  updatedAt: DateTime!
  """When the setup was last verified."""
  verifiedAt: DateTime
}

"""The result of creating a template."""
type WhatsAppCreateTemplateResultGql {
  """Where the provider's approval stands."""
  approvalStatus: String
  """Why it failed, if it did."""
  detail: String
  """The name of the template."""
  name: String
  """True when the template was created."""
  ok: Boolean!
  """The ID of the template at the provider."""
  templateId: String
}

"""Filters for the WhatsApp message log."""
input WhatsAppMessageLogFilterInput {
  "Maximum number of records to return."
  limit: Int
}

"""One WhatsApp message in the log."""
type WhatsAppMessageLogGql {
  "When the record was created."
  createdAt: DateTime!
  """Why it failed, if it did."""
  error: String
  "The unique ID of this record."
  id: ID!
  """The provider that sent it."""
  provider: String!
  """The provider's ID for the message."""
  providerMessageId: String
  """The ID of that document."""
  referenceId: String
  """The kind of document the message is about."""
  referenceType: String
  """Where the message stands."""
  status: String!
  """The name of the template."""
  templateName: String
  """The phone number it went to."""
  toPhone: String!
}

"""A WhatsApp provider a tenant can connect."""
enum WhatsAppProvider {
  """Interakt."""
  INTERAKT
  """Respond.io."""
  RESPOND_IO
}

"""
What the setup's provider supports. The console hides actions it cannot do.
"""
type WhatsAppProviderCapabilitiesGql {
  """True when templates can be created here."""
  createTemplate: Boolean!
  """True when a channel must be chosen."""
  requiresChannel: Boolean!
}

"""One button of a template."""
input WhatsAppTemplateButtonInput {
  """The number the button calls. Required for PHONE_NUMBER buttons."""
  phoneNumber: String
  """The text on the button."""
  text: String!
  """QUICK_REPLY, URL or PHONE_NUMBER."""
  type: String!
  """The address the button opens. Required for URL buttons."""
  url: String
}

"""A WhatsApp template from the provider."""
type WhatsAppTemplateGql {
  """The text of the template."""
  bodyText: String
  """The category of the template."""
  category: String
  """The language code of the template."""
  languageCode: String!
  """The name of the template."""
  name: String!
  """The approval status of the template."""
  status: String
}

"""
The templates fetched from the provider. When ok is false, enter the template by hand.
"""
type WhatsAppTemplatesResultGql {
  """Why it failed, if it did."""
  detail: String
  """True when the templates were fetched."""
  ok: Boolean!
  """The templates."""
  templates: [WhatsAppTemplateGql!]!
}

"""The result of a test message."""
type WhatsAppTestResultGql {
  """Why it failed, if it did."""
  detail: String
  """True when the test message was sent."""
  ok: Boolean!
  """The provider's ID for the message."""
  providerMessageId: String
}

"""The setup of one trigger for the organization."""
type WhatsAppTriggerConfigGql {
  """True when the trigger is on."""
  enabled: Boolean!
  """The key of the trigger."""
  key: String!
  """The language code of the template."""
  languageCode: String!
  """The name of the template to send."""
  templateName: String!
}

"""A trigger from the catalog. It drives the settings page."""
type WhatsAppTriggerDefinitionGql {
  """The group the trigger belongs to."""
  category: String!
  """What the trigger does."""
  description: String!
  """The key of the trigger."""
  key: String!
  """The name of the trigger."""
  label: String!
  """
  UTILITY, which is never gated on consent, or MARKETING, which needs opt-in and is subject to caps and quiet hours.
  """
  purpose: String!
  """The kind of document the message is about."""
  referenceType: String!
  """The event that fires the trigger."""
  sourceEvent: String!
}

"""Approval workflow settings."""
input WorkflowSettingsInput {
  """True to let approvers hand over to someone else."""
  allowDelegation: Boolean
  """The amount below which approval is automatic."""
  autoApproveThreshold: String
  """True to use approval workflows."""
  enableWorkflows: Boolean
  """True to escalate approvals that wait too long."""
  escalationEnabled: Boolean
  """How long an approval may wait before it is escalated."""
  escalationTimeout: String
  """True to notify when approved."""
  notifyOnApproval: Boolean
  """True to notify when rejected."""
  notifyOnRejection: Boolean
  """True to ask approvers at the same time."""
  parallelApprovals: Boolean
  """True when approvals need a comment."""
  requireComments: Boolean
  """True to keep the approval history."""
  trackHistory: Boolean
}

"""An area inside a warehouse, such as receiving, storage or shipping."""
type Zone {
  """The storage capacity of the zone."""
  capacity: Int
  """The zone code."""
  code: String!
  "When the record was created."
  createdAt: DateTime!
  """How much of the capacity is in use."""
  currentOccupancy: Int
  "When the record was deleted. Empty while the record is live."
  deletedAt: DateTime
  "The ID of the user who deleted the record."
  deletedBy: String
  """What the zone is used for."""
  description: String
  "The ID of the user who created the record."
  enteredBy: String!
  """The current humidity in the zone."""
  humidity: Float
  """The highest humidity the zone should stay at."""
  humidityMax: Float
  """The lowest humidity the zone should stay at."""
  humidityMin: Float
  "The unique ID of this record."
  id: ID!
  "Whether the record is active."
  isActive: Boolean!
  "Additional data attached to the record, as JSON."
  metadata: JSON!
  """The zone name."""
  name: String!
  """The current temperature in the zone."""
  temperature: Float
  """The highest temperature the zone should stay at."""
  temperatureMax: Float
  """The lowest temperature the zone should stay at."""
  temperatureMin: Float
  """The kind of zone."""
  type: ZoneType!
  "When the record was last changed."
  updatedAt: DateTime!
  "The ID of the user who last changed the record."
  updatedBy: String!
  """The share of the capacity in use, in percent."""
  utilizationRate: Float
  "The ID of the warehouse."
  warehouseId: String!
}

"""The type of warehouse zone"""
enum ZoneType {
  """Where orders are packed."""
  PACKING
  """Where items are picked."""
  PICKING
  """Where stock is held for checking."""
  QUARANTINE
  """Where goods arrive."""
  RECEIVING
  """Where returns are handled."""
  RETURNS
  """Where orders wait for the courier."""
  SHIPPING
  """Long-term storage."""
  STORAGE
}
