Skip to main content

Import customers and their properties

POST/api/v1/customers/import

Brings in up to 100 rows, each a customer and, when it has an address, one property of theirs. Send dry_run: true first: it answers exactly what the same rows will do and saves nothing. A dry run is never replayed: asked again, it answers for the workspace as it is then. A row whose customer is already here creates nobody. A customer is recognised by email, then by phone (its digits, seven or more, with a leading 44 read as 0), then by name; archived customers are not matched. A name matches only when nothing contradicts it: two people of one name are two customers when both have an email and the emails differ, or both have a phone and the phones differ. A matched customer is only completed: the row fills in company_name, email, phone, notes and billing_address where they are blank, and changes nothing that is filled in. The row's property is added unless the customer has it already, by postcode and first line or by its name. Two addresses that both have a second line and differ in it are two properties. Rows are taken in order and each sees what the rows before it did, so two rows for one person make one customer with two properties. A dry run cannot see what an earlier dry run would have created, so keep one person's rows in one request. A row that cannot be saved is skipped with its reason in detail, and the others are imported. An address that cannot be a property is left out and its customer is kept. Nobody is emailed. The request is saved whole or not at all, so one that fails can be sent again with the same Idempotency-Key; sent again under a new key, its rows match the customers it made and create nothing.

  • Needs an API key, and runs with the access of the member who made the key.
  • Send an Idempotency-Key. The same key with the same request within 24 hours gives the first answer again and changes nothing.
  • A connected AI assistant can use it too, as importCustomers.

Parameters

Headers

  • Idempotency-Keystringrequired

    Unique user-scoped key for safely retrying this mutation for 24 hours.

    At least 1 character. Up to 200 characters.

Request body

Sent as application/json.

  • dry_runboolean

    Answer what the rows would do and save nothing.

    Default: false.

  • rowsarray of objectrequired

    More than 100 rows is refused with the error code `too_many_rows`.

    At least 1 item. Up to 100 items.

    Each item(3)
    • rowinteger

      The row's number in the file it came from, repeated in its result. Defaults to its place in `rows`, from 1.

    • customerobjectrequired

      The fields createCustomer takes. A row without a `name` is skipped.

      Fields(12)
      • lock_versioninteger

        At least 0.

      • namestring

      • company_namestring or null

      • emailstring (email) or null

      • phonestring or null

      • payment_terms_daysinteger

        At least 0.

      • notesstring or null

      • automatic_emailsboolean

        Deprecated: use `invoice_reminders`, `quote_follow_ups` and `visit_reminders`, which it stands for. It reads false only when all three are `off`. Writing false sets all three to `off`; writing true sets all three to `default` when they were all `off`, and otherwise changes nothing. Sent with any of the three, it is ignored. It changes nothing about emails a person sends.

        Default: true. Deprecated.

      • invoice_remindersstring

        Whether this customer is reminded by email about their overdue invoices.

        One of: default, on, off. Default: "default".

      • quote_follow_upsstring

        Whether this customer's quotes awaiting an answer are followed up by email.

        One of: default, on, off. Default: "default".

      • visit_remindersstring

        Whether this customer is reminded by email of their visits the day before.

        One of: default, on, off. Default: "default".

      • billing_addressobject or null

        Fields(6)
        • address_line_1stringrequired

        • address_line_2string or null

        • citystringrequired

        • regionstring or null

        • postal_codestringrequired

        • country_codestringrequired

          At least 2 characters. Up to 2 characters.

    • propertyobject or null

      The row's address, with the fields createCustomerProperty takes. Leave it out, or send null, for a customer alone. One without a street, town and postcode is left out. Without a `country_code` it is in GB.

      Fields(12)
      • lock_versioninteger

        At least 0.

      • namestring or null

      • address_line_1string

      • address_line_2string or null

      • citystring

      • regionstring or null

      • postal_codestring

      • country_codestring

        At least 2 characters. Up to 2 characters.

      • access_notesstring or null

      • lawn_area_m2string or null

        The lawn at the property in square metres, with up to two decimal places, or null when it has not been measured. Use it as the quantity of lawn work priced per square metre, such as turfing. A patio or decking is priced the same way and is some other size.

        Matches ^\d{1,8}(\.\d{1,2})?$.

      • billing_namestring or null

        Who quotes and invoices for work here are addressed to, such as a letting agent. Defaults to the customer.

      • billing_addressobject or null

        Where quotes and invoices for work here are sent, before the customer's billing address. Omit to keep, null to clear.

        Fields(6)
        • address_line_1stringrequired

        • address_line_2string or null

        • citystringrequired

        • regionstring or null

        • postal_codestringrequired

        • country_codestringrequired

          At least 2 characters. Up to 2 characters.

Responses

200What each row did, or with dry_run would do.

  • dataobjectrequired

    Fields(5)
    • dry_runbooleanrequired

    • createdintegerrequired

      Rows with the outcome `create`.

      At least 0.

    • matchedintegerrequired

      Rows with the outcome `match`.

      At least 0.

    • skippedintegerrequired

      Rows with the outcome `skip`.

      At least 0.

    • resultsarray of objectrequired

      One result for each row, in the order they were sent.

      Each item(8)
      • rowintegerrequired

      • outcomestringrequired

        `create` is a new customer, `match` a customer who is already here, `skip` a row that was not imported.

        One of: create, match, skip.

      • matched_onstring or nullrequired

        What a matched customer was recognised by.

        One of: email, phone, name.

      • matched_rowinteger or nullrequired

        The earlier row of this request that created the matched customer. Null when they were here before it.

      • customer_idstring (uuid) or nullrequired

        The customer created or matched. Null for a skipped row, and in a dry run for a customer it would create.

      • filledarray of stringrequired

        The fields of a matched customer that were blank and that this row filled in.

      • propertystringrequired

        What became of the row's address: `create` a new property, `match` one the customer already had, `skip` one that could not be saved, `none` when the row had no address.

        One of: create, match, skip, none.

      • detailstring or nullrequired

        Why a row was skipped or its address left out, for a person to read.

A refusal answers in the one error shape every operation shares.

Example

A request our own tests send. The ids are made up: put your own in their place.

curl -X POST "https://app.tradesender.co.uk/api/v1/customers/import" \
  -H "Authorization: Bearer $TRADESENDER_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "rows": [
    {
      "row": 2,
      "customer": {
        "name": "Taylor Home",
        "email": "taylor@example.test",
        "phone": "07700 900123"
      },
      "property": {
        "address_line_1": "7 Orchard Close",
        "city": "London",
        "postal_code": "N1 3CC"
      }
    },
    {
      "row": 3,
      "customer": {
        "name": "Imported Customer",
        "email": "imported@example.test"
      },
      "property": {
        "name": "Home",
        "address_line_1": "1 Mill Lane",
        "city": "Leeds",
        "postal_code": "LS1 1AA"
      }
    },
    {
      "row": 4,
      "customer": {
        "name": "Imported Customer",
        "email": "imported@example.test"
      },
      "property": {
        "name": "Their mother'\''s",
        "address_line_1": "9 Shore Road",
        "city": "Leeds",
        "postal_code": "LS2 2BB"
      }
    },
    {
      "row": 5,
      "customer": {
        "name": ""
      },
      "property": null
    }
  ]
}'