Platform Release 12 July 2018

The following changes were introduced in the GraphQL schema (in SDL format):

extend type Query {
  customer(
    "Queries a customer with specified ID"
    id: String,

    "Queries a customer with specified key"
    key: String,

    "Queries a customer with specified email token"
    emailToken: String,

    "Queries a customer with specified password token"
    passwordToken: String): Customer
  customers(where: String, sort: [String!], limit: Int, offset: Int): CustomerQueryResult!

  """
  This field can only be used with an access token created with the password flow or with an anonymous session.
  
  It gives access to the data that is specific to the customer or the anonymous session linked to the access token.
  """
  me: Me
}

extend type Mutation {
  customerChangeMyPassword(version: Long!, currentPassword: String!, newPassword: String!): Customer
  customerChangePassword(id: String!, version: Long!, currentPassword: String!, newPassword: String!): Customer

  "Verifies customer's email using a token."
  customerConfirmEmail(version: Long, tokenValue: String!): Customer
  customerConfirmMyEmail(tokenValue: String!): Customer
  customerCreateEmailVerificationToken(id: String!, version: Long,

    "The validity of the created token in minutes."
    ttlMinutes: Int!): CustomerToken!

  "The token value is used to reset the password of the customer with the given email. The token is valid only for 10 minutes."
  customerCreatePasswordResetToken(email: String!,

    "The validity of the created token in minutes."
    ttlMinutes: Int): CustomerToken
  customerResetMyPassword(tokenValue: String!, newPassword: String!): Customer

  """
  The following workflow can be used to reset the customer’s password:
  
  1. Create a password reset token and send it embedded in a link to the customer.
  2. When the customer clicks on the link, you may optionally retrieve customer by password token.
  3. When the customer entered new password, use reset customer’s password to reset the password.
  """
  customerResetPassword(version: Long, tokenValue: String!, newPassword: String!): Customer

  """
  Retrieves the authenticated customer (a customer that matches the given email/password pair).
  
  There may be carts and orders created before the sign in that should be assigned to the customer account. With the `anonymousCartId`, a single anonymous cart can be assigned. With the `anonymousId`, all orders and carts that have this `anonymousId` set will be assigned to the customer.
  If both `anonymousCartId` and `anonymousId` are given, the anonymous cart must have the `anonymousId`.
  
  Additionally, there might also exist one or more active customer carts from an earlier session. On customer sign in there are several ways how to proceed with this cart and the cart referenced by the `anonymousCartId`.
  
  * If the customer does not have a cart yet, the anonymous cart becomes the customer's cart.
  * If the customer already has one or more carts, the content of the anonymous cart will be copied to the customer's active cart that has been modified most recently.
  
    In this case the `CartState` of the anonymous cart gets changed to `Merged` while the customer's cart remains the `Active` cart.
  
    If a `LineItem` in the anonymous cart matches an existing line item, or a `CustomLineItem` matches an existing custom line item in the customer's cart, the maximum quantity of both line items is used as the new quantity.
  
    `ItemShippingDetails` are copied from the item with the highest quantity.
  
    If `itemShippingAddresses` are different in the two carts, the resulting cart contains the addresses of both the customer cart and the anonymous cart.
  
    Note, that it is not possible to merge carts that differ in their currency (set during creation of the cart).
  
  If a cart is is returned as part of the `CustomerSignInResult`, it has been recalculated (it will have up-to-date prices, taxes and discounts, and invalid line items have been removed).
  """
  customerSignIn(draft: CustomerSignInDraft!): CustomerSignInResult!

  """
  Retrieves the authenticated customer (a customer that matches the given email/password pair).
  
  If used with an access token for Anonymous Sessions, all orders and carts belonging to the `anonymousId` will be assigned to the newly created customer.
  
  * If the customer does not have a cart yet, the anonymous cart that was modified most recently becomes the customer's cart.
  * If the customer already has a cart, the most recently modified anonymous cart will be handled according to the `AnonymousCartSignInMode`.
  
  If a cart is is returned as part of the `CustomerSignInResult`, it has been recalculated (it will have up-to-date prices, taxes and discounts, and invalid line items have been removed).
  """
  customerSignMeIn(draft: CustomerSignMeInDraft!): CustomerSignInResult!

  "If used with an access token for Anonymous Sessions, all orders and carts belonging to the anonymousId will be assigned to the newly created customer."
  customerSignMeUp(draft: CustomerSignMeUpDraft!): CustomerSignInResult!

  "Creates a customer. If an anonymous cart is given then the cart is assigned to the created customer and the version number of the Cart will increase. If the id of an anonymous session is given, all carts and orders will be assigned to the created customer."
  customerSignUp(draft: CustomerSignUpDraft!): CustomerSignInResult!
  deleteCustomer(
    "Queries with specified ID"
    id: String,

    "Queries with specified key"
    key: String, version: Long!, personalDataErasure: Boolean = false): Customer
  deleteMyCustomer(version: Long!, personalDataErasure: Boolean = false): Customer
  updateCustomer(
    "Queries with specified ID"
    id: String,

    "Queries with specified key"
    key: String, version: Long!, actions: [CustomerUpdateAction!]!): Customer
  updateMyCustomer(version: Long!, actions: [MyCustomerUpdateAction!]!): Customer
}

input AddCustomerAddress {
  address: AddressInput!
}

input AddCustomerBillingAddressId {
  addressId: String!
}

input AddCustomerShippingAddressId {
  addressId: String!
}

"An address represents a a postal address."
type Address {
  id: String
  title: String
  salutation: String
  firstName: String
  lastName: String
  streetName: String
  streetNumber: String
  additionalStreetInfo: String
  postalCode: String
  city: String
  region: String
  state: String
  country: Country!
  company: String
  department: String
  building: String
  apartment: String
  pOBox: String
  contactInfo: AddressContactInfo!
  additionalAddressInfo: String
  externalId: String
  key: String
}

type AddressContactInfo {
  phone: String
  mobile: String
  email: String
  fax: String
}

input AddressInput {
  id: String
  title: String
  salutation: String
  firstName: String
  lastName: String
  streetName: String
  streetNumber: String
  additionalStreetInfo: String
  postalCode: String
  city: String
  region: String
  state: String
  country: Country!
  company: String
  department: String
  building: String
  apartment: String
  pOBox: String
  phone: String
  mobile: String
  email: String
  fax: String
  additionalAddressInfo: String
  key: String
}

enum AnonymousCartSignInMode {
  "The anonymous cart is used as new active customer cart. No `LineItem`s get merged."
  UseAsNewActiveCustomerCart

  """
  `LineItem`s of the anonymous cart will be copied to the customer’s active cart that has been modified most recently.
  
  The `CartState` of the anonymous cart gets changed to `Merged` while the `CartState` of the customer’s cart remains `Active`.
  
  `CustomLineItems` and `CustomFields` of the anonymous cart will not be copied to the customers cart.
  
  If a `LineItem` in the anonymous cart matches an existing line item in the customer’s cart (same product ID and variant ID), the maximum quantity of both LineItems is used as the new quantity. In that case `CustomFields` on the `LineItem` of the anonymous cart will not be in the resulting `LineItem`.
  """
  MergeWithExistingCustomerCart
}

input ChangeCustomerAddress {
  addressId: String!
  address: AddressInput!
}

input ChangeCustomerEmail {
  email: String!
}

"A customer is a person purchasing products. Carts, Orders and Reviews can be associated to a customer."
type Customer implements Versioned {
  id: String!
  version: Long!
  customerNumber: String
  email: String!
  password: String!
  addresses: [Address!]!
  defaultShippingAddressId: String
  defaultBillingAddressId: String
  shippingAddressIds: [String!]!
  billingAddressIds: [String!]!
  isEmailVerified: Boolean!
  customerGroupRef: Reference
  externalId: String
  key: String
  dateOfBirth: Date
  companyName: String
  vatId: String
  createdAt: DateTime!
  lastModifiedAt: DateTime!
  lastMessageSequenceNumber: Long!
  firstName: String
  lastName: String
  middleName: String
  title: String
  locale: Locale
  salutation: String
  customerGroup: CustomerGroup
  defaultShippingAddress: Address
  defaultBillingAddress: Address
  shippingAddresses: [Address!]!
  billingAddresses: [Address!]!

  "This field contains non-typed data. Consider using `customFields` as a typed alternative."
  customFieldsRaw(
    """
    The names of the custom fields to include.
    
    If neither `includeNames` nor `excludeNames` are provided, then all custom fields are returned.
    """
    includeNames: [String!],

    """
    The names of the custom fields to exclude.
    
    If neither `includeNames` nor `excludeNames` are provided, then all custom fields are returned.
    """
    excludeNames: [String!]): [RawCustomField!]

  "Custom fields"
  customFields: Type

  "Custom fields are returned as a list instead of an object structure."
  customFieldList(
    """
    The names of the custom fields to include.
    
    If neither `includeNames` nor `excludeNames` are provided, then all attributes are returned.
    """
    includeNames: [String!],

    """
    The names of the custom fields to exclude.
    
    If neither `includeNames` nor `excludeNames` are provided, then all attributes are returned.
    """
    excludeNames: [String!]): [CustomField!]
}

type CustomerQueryResult {
  offset: Int!
  count: Int!
  total: Long!
  results: [Customer!]!
}

input CustomerSignInDraft {
  email: String!
  password: String!
  anonymousCartId: String
  anonymousCartSignInMode: AnonymousCartSignInMode = MergeWithExistingCustomerCart
  anonymousId: String
  updateProductData: Boolean = false
}

type CustomerSignInResult {
  customer: Customer!
}

input CustomerSignMeInDraft {
  email: String!
  password: String!
  activeCartSignInMode: AnonymousCartSignInMode = MergeWithExistingCustomerCart
  updateProductData: Boolean = false
}

input CustomerSignMeUpDraft {
  email: String!
  password: String!
  firstName: String
  lastName: String
  middleName: String
  title: String
  dateOfBirth: Date
  companyName: String
  vatId: String
  addresses: [AddressInput!] = []

  "The index of the address in the `addresses` list. The `defaultBillingAddressId` of the customer will be set to the ID of that address."
  defaultBillingAddress: Int

  "The index of the address in the `addresses` list. The `defaultShippingAddressId` of the customer will be set to the ID of that address."
  defaultShippingAddress: Int

  "The indices of the shipping addresses in the `addresses` list. The `shippingAddressIds` of the `Customer` will be set to the IDs of that addresses."
  shippingAddresses: [Int!] = []

  "The indices of the billing addresses in the `addresses` list. The `billingAddressIds` of the customer will be set to the IDs of that addresses."
  billingAddresses: [Int!] = []
  custom: CustomFieldsDraft
  locale: Locale
  salutation: String
  key: String
}

input CustomerSignUpDraft {
  email: String!
  password: String!
  firstName: String
  lastName: String
  middleName: String
  title: String
  dateOfBirth: Date
  companyName: String
  vatId: String
  addresses: [AddressInput!] = []

  "The index of the address in the `addresses` list. The `defaultBillingAddressId` of the customer will be set to the ID of that address."
  defaultBillingAddress: Int

  "The index of the address in the `addresses` list. The `defaultShippingAddressId` of the customer will be set to the ID of that address."
  defaultShippingAddress: Int

  "The indices of the shipping addresses in the `addresses` list. The `shippingAddressIds` of the `Customer` will be set to the IDs of that addresses."
  shippingAddresses: [Int!] = []

  "The indices of the billing addresses in the `addresses` list. The `billingAddressIds` of the customer will be set to the IDs of that addresses."
  billingAddresses: [Int!] = []
  custom: CustomFieldsDraft
  locale: Locale
  salutation: String
  key: String
  customerNumber: String
  anonymousCartId: String
  externalId: String
  customerGroup: ResourceIdentifierInput
  isEmailVerified: Boolean
  anonymousId: String
}

type CustomerToken {
  id: String!
  customerId: String!
  createdAt: DateTime!
  expiresAt: DateTime!
  value: String!
}

input CustomerUpdateAction {
  setFirstName: SetCustomerFirstName
  setLastName: SetCustomerLastName
  setMiddleName: SetCustomerMiddleName
  setTitle: SetCustomerTitle
  setSalutation: SetCustomerSalutation
  changeEmail: ChangeCustomerEmail
  addAddress: AddCustomerAddress
  setCustomerGroup: SetCustomerCustomerGroup
  changeAddress: ChangeCustomerAddress
  removeAddress: RemoveCustomerAddress
  setDefaultShippingAddress: SetCustomerDefaultShippingAddress
  setDefaultBillingAddress: SetCustomerDefaultBillingAddress
  addShippingAddressId: AddCustomerShippingAddressId
  removeShippingAddressId: RemoveCustomerShippingAddressId
  addBillingAddressId: AddCustomerBillingAddressId
  removeBillingAddressId: RemoveCustomerBillingAddressId
  setCustomerNumber: SetCustomerCustomerNumber
  setExternalId: SetCustomerExternalId
  setDateOfBirth: SetCustomerDateOfBirth
  setCompanyName: SetCustomerCompanyName
  setVatId: SetCustomerVatId
  setLocale: SetCustomerLocale
  setKey: SetCustomerKey
  setCustomType: SetCustomerCustomType
  setCustomField: SetCustomerCustomField
}

type Me {
  customer: Customer
}

input MyCustomerUpdateAction {
  setFirstName: SetCustomerFirstName
  setLastName: SetCustomerLastName
  setMiddleName: SetCustomerMiddleName
  setTitle: SetCustomerTitle
  setSalutation: SetCustomerSalutation
  changeEmail: ChangeCustomerEmail
  addAddress: AddCustomerAddress
  changeAddress: ChangeCustomerAddress
  removeAddress: RemoveCustomerAddress
  setDefaultShippingAddress: SetCustomerDefaultShippingAddress
  setDefaultBillingAddress: SetCustomerDefaultBillingAddress
  addShippingAddressId: AddCustomerShippingAddressId
  removeShippingAddressId: RemoveCustomerShippingAddressId
  addBillingAddressId: AddCustomerBillingAddressId
  removeBillingAddressId: RemoveCustomerBillingAddressId
  setDateOfBirth: SetCustomerDateOfBirth
  setCompanyName: SetCustomerCompanyName
  setVatId: SetCustomerVatId
  setLocale: SetCustomerLocale
  setCustomType: SetCustomerCustomType
  setCustomField: SetCustomerCustomField
}

input RemoveCustomerAddress {
  addressId: String!
}

input RemoveCustomerBillingAddressId {
  addressId: String!
}

input RemoveCustomerShippingAddressId {
  addressId: String!
}

input SetCustomerCompanyName {
  companyName: String
}

input SetCustomerCustomField {
  name: String!
  value: String
}

input SetCustomerCustomType {
  typeId: String
  typeKey: String
  type: ResourceIdentifierInput
  fields: [CustomFieldInput!]
}

input SetCustomerCustomerGroup {
  customerGroup: ResourceIdentifierInput
}

input SetCustomerCustomerNumber {
  customerNumber: String
}

input SetCustomerDateOfBirth {
  dateOfBirth: Date
}

input SetCustomerDefaultBillingAddress {
  addressId: String
}

input SetCustomerDefaultShippingAddress {
  addressId: String
}

input SetCustomerExternalId {
  externalId: String
}

input SetCustomerFirstName {
  firstName: String
}

input SetCustomerKey {
  key: String
}

input SetCustomerLastName {
  lastName: String
}

input SetCustomerLocale {
  locale: Locale
}

input SetCustomerMiddleName {
  middleName: String
}

input SetCustomerSalutation {
  salutation: String
}

input SetCustomerTitle {
  title: String
}

input SetCustomerVatId {
  vatId: String
}