DevelopersAPI reference

Customers API

REST endpoints for customers in SKUFlow: 19 operations with parameters, request and response fields, permissions and curl examples.

Base URL: https://app.skuflow.ai/api. Every call needs Authorization: Bearer skf_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.

OperationEndpointRisk
List customersGET /organizations/{organizationId}/customersread
Create a customerPOST /organizations/{organizationId}/customerswrite
All customers that are not archived, for pickersGET /organizations/{organizationId}/customers/optionsread
Get a customerGET /organizations/{organizationId}/customers/{customerId}read
Update a customerPATCH /organizations/{organizationId}/customers/{customerId}write
Delete a customerDELETE /organizations/{organizationId}/customers/{customerId}sensitive
List a customer's contactsGET /organizations/{organizationId}/customers/{customerId}/contactsread
Add a contactPOST /organizations/{organizationId}/customers/{customerId}/contactswrite
Update a contactPATCH /organizations/{organizationId}/customers/{customerId}/contacts/{contactId}write
Delete a contactDELETE /organizations/{organizationId}/customers/{customerId}/contacts/{contactId}sensitive
List notes on a customer or propertyGET /organizations/{organizationId}/{ownerType}/{ownerId}/notesread
Add a notePOST /organizations/{organizationId}/{ownerType}/{ownerId}/noteswrite
Edit or pin a notePATCH /organizations/{organizationId}/{ownerType}/{ownerId}/notes/{noteId}write
Delete a noteDELETE /organizations/{organizationId}/{ownerType}/{ownerId}/notes/{noteId}sensitive
List files on a customer or propertyGET /organizations/{organizationId}/{ownerType}/{ownerId}/attachmentsread
Start a file uploadPOST /organizations/{organizationId}/{ownerType}/{ownerId}/attachmentswrite
Confirm a finished uploadPOST /organizations/{organizationId}/{ownerType}/{ownerId}/attachments/{attachmentId}/confirmwrite
Delete a fileDELETE /organizations/{organizationId}/{ownerType}/{ownerId}/attachments/{attachmentId}sensitive
Attach a file (content in the request)POST /organizations/{organizationId}/{ownerType}/{ownerId}/attachments/contentwrite

List customers

GET /organizations/{organizationId}/customers

Customers by name, filtered by text (name, company, email, phone), status, type, tag or lead source; paged with a total. Archived customers are left out unless status=ARCHIVED. Read-only. Use GET /customers/options for a picker list.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolcustomers_list (toolset customers, in the default set)

Parameters

NameInTypeRequiredDescription
queryquerystringNoFree-text search over the list's names, numbers and contact details. Up to 200 characters.
statusqueryenumNoOne of LEAD, ACTIVE, INACTIVE, ARCHIVED.
typequeryenumNoOne of RESIDENTIAL, COMMERCIAL.
tagquerystringNoUp to 200 characters.
leadSourceIdquerystringNo
limitqueryintegerNoPage size, 1–200. Default 50.
offsetqueryintegerNoRows to skip; the answer's total counts every match. Default 0.

Example

curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstringCustomer id.
items[].organizationIdstring
items[].typeenumOne of RESIDENTIAL, COMMERCIAL.
items[].titlestring or null
items[].firstNamestring or null
items[].lastNamestring or null
items[].companyNamestring or null
items[].namestringDisplay name, derived from the person or company name.
items[].statusenumLEAD until the first sale, then ACTIVE; ARCHIVED customers leave the lists. One of LEAD, ACTIVE, INACTIVE, ARCHIVED.
items[].emailstring or nullThe primary contact's main email.
items[].phonestring or nullThe primary contact's main phone.
items[].addressstring or nullBilling address (street).
items[].address2string or null
items[].citystring or null
items[].statestring or null
items[].zipstring or null
items[].countrystring or null
items[].leadSourceIdstring or nullFrom GET /lead-sources.
items[].tagsarray of string
items[].paymentTermsenumInvoice due date rule; CUSTOM uses paymentTermsDays. One of DUE_ON_RECEIPT, NET_7, NET_15, NET_30, NET_45, NET_60, CUSTOM.
items[].paymentTermsDaysinteger or nullDays to pay, for CUSTOM terms.
items[].taxExemptbooleanInvoices and quotes carry no tax.
items[].taxExemptIdstring or null
items[].creditLimitCentsinteger or nullCredit limit in integer cents; null = none.
items[].doNotServicebooleanQuote and invoice screens warn before new work is sold.
items[].doNotServiceReasonstring or null
items[].allowEmailboolean
items[].allowSmsboolean
items[].allowMarketingboolean
items[].notesstring or null
items[].customFieldsanyCustom field values by key (definitions: GET /custom-fields).
items[].createdAtstring (date-time)
items[].updatedAtstring (date-time)
items[].contactsarray of objectContacts, primary first.
items[].contacts[].idstringContact id.
items[].contacts[].customerIdstring
items[].contacts[].firstNamestring or null
items[].contacts[].lastNamestring or null
items[].contacts[].jobTitlestring or null
items[].contacts[].rolesarray of enumWhat the contact is for; the primary contact has PRIMARY.
items[].contacts[].isPrimarybooleanThe primary contact; its main email and phone mirror onto the customer.
items[].contacts[].notesstring or null
items[].contacts[].createdAtstring (date-time)
items[].contacts[].updatedAtstring (date-time)
items[].contacts[].methodsarray of objectPhones and emails, primary first.
items[].leadSourceobject or null
items[].leadSource.idstring
items[].leadSource.namestring
items[].balanceCentsintegerOpen balance: due on SENT/OVERDUE invoices less unapplied deposits; negative = in credit, in integer cents.
items[].lifetimeValueCentsintegerEvery payment collected, net of refunds, tips excluded, in integer cents.
items[].overCreditLimitbooleanThe balance is above creditLimitCents.
totalintegerHow many match the filters, across all pages.

Create a customer

POST /organizations/{organizationId}/customers

Creates a customer, optionally with contacts (else one primary contact from the names, email and phone) and an address (property) the customer owns, e.g. their ship-to location. Custom field values are validated against GET /custom-fields. Search GET /customers first to avoid duplicates. Nothing is sent to the customer. Returns the customer.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolcustomers_create (toolset customers, in the default set)

Request body

FieldTypeRequiredDescription
typeenumNoOne of RESIDENTIAL, COMMERCIAL.
titlestring or nullNo
firstNamestring or nullNo
lastNamestring or nullNo
companyNamestring or nullNo
namestringNo
statusenumNoOne of LEAD, ACTIVE, INACTIVE, ARCHIVED.
emailempty string or string (email) or nullNo
phonestring or nullNo
addressstring or nullNo
address2string or nullNo
citystring or nullNo
statestring or nullNo
zipstring or nullNo
countrystring or nullNo
leadSourceIdstring or nullNo
tagsarray of stringNoUp to 100 items.
paymentTermsenumNoOne of DUE_ON_RECEIPT, NET_7, NET_15, NET_30, NET_45, NET_60, CUSTOM.
paymentTermsDaysinteger or nullNo0–3650.
taxExemptbooleanNo
taxExemptIdstring or nullNo
creditLimitCentsinteger or nullNo0–1000000000.
doNotServicebooleanNo
doNotServiceReasonstring or nullNo
allowEmailbooleanNo
allowSmsbooleanNo
allowMarketingbooleanNo
notesstring or nullNo
customFieldsobjectNo
contactsarray of objectNoUp to 50 items.
contacts[].firstNamestring or nullNo
contacts[].lastNamestring or nullNo
contacts[].jobTitlestring or nullNo
contacts[].rolesarray of enumNoUp to 7 items.
contacts[].isPrimarybooleanNo
contacts[].notesstring or nullNo
contacts[].methodsarray of objectNoUp to 50 items.
contacts[].methods[].kindenumYesOne of PHONE, EMAIL.
contacts[].methods[].labelenumNoOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
contacts[].methods[].valuestringYesUp to 500 characters.
contacts[].methods[].isPrimarybooleanNo
contacts[].methods[].smsConsentenumNoOne of UNKNOWN, GRANTED, DENIED.
propertyobject or nullNo
property.namestring or nullNoUp to 500 characters.
property.addressstring or nullNoUp to 500 characters.
property.address2string or nullNoUp to 500 characters.
property.citystring or nullNoUp to 500 characters.
property.countystring or nullNoCounty (or parish), for tax rules that name one. Up to 500 characters.
property.statestring or nullNoUp to 500 characters.
property.zipstring or nullNoUp to 500 characters.
property.countrystring or nullNoUp to 500 characters.
property.propertyTypeenumNoOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
property.contactNamestring or nullNoUp to 500 characters.
property.contactPhonestring or nullNoUp to 500 characters.
property.contactEmailempty string or string (email) or nullNo
property.timezonestringNoAn IANA timezone, e.g. America/Chicago. Up to 100 characters.
property.accessInstructionsstring or nullNoDelivery or drop-off instructions for this address. Up to 5000 characters.
property.tagsarray of stringNoUp to 100 items.
property.taxRatenumber or nullNoTax rate in percent for sales shipped here; null = the business default. -1000–1000.
property.customFieldsobjectNo
property.roleenumNoOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"RESIDENTIAL","title":"string","firstName":"string"}'

Response

201: the answer's fields
FieldTypeDescription
idstringCustomer id.
organizationIdstring
typeenumOne of RESIDENTIAL, COMMERCIAL.
titlestring or null
firstNamestring or null
lastNamestring or null
companyNamestring or null
namestringDisplay name, derived from the person or company name.
statusenumLEAD until the first sale, then ACTIVE; ARCHIVED customers leave the lists. One of LEAD, ACTIVE, INACTIVE, ARCHIVED.
emailstring or nullThe primary contact's main email.
phonestring or nullThe primary contact's main phone.
addressstring or nullBilling address (street).
address2string or null
citystring or null
statestring or null
zipstring or null
countrystring or null
leadSourceIdstring or nullFrom GET /lead-sources.
tagsarray of string
paymentTermsenumInvoice due date rule; CUSTOM uses paymentTermsDays. One of DUE_ON_RECEIPT, NET_7, NET_15, NET_30, NET_45, NET_60, CUSTOM.
paymentTermsDaysinteger or nullDays to pay, for CUSTOM terms.
taxExemptbooleanInvoices and quotes carry no tax.
taxExemptIdstring or null
creditLimitCentsinteger or nullCredit limit in integer cents; null = none.
doNotServicebooleanQuote and invoice screens warn before new work is sold.
doNotServiceReasonstring or null
allowEmailboolean
allowSmsboolean
allowMarketingboolean
notesstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields).
createdAtstring (date-time)
updatedAtstring (date-time)
contactsarray of object
contacts[].idstringContact id.
contacts[].customerIdstring
contacts[].firstNamestring or null
contacts[].lastNamestring or null
contacts[].jobTitlestring or null
contacts[].rolesarray of enumWhat the contact is for; the primary contact has PRIMARY.
contacts[].isPrimarybooleanThe primary contact; its main email and phone mirror onto the customer.
contacts[].notesstring or null
contacts[].createdAtstring (date-time)
contacts[].updatedAtstring (date-time)
contacts[].methodsarray of objectPhones and emails, primary first.
contacts[].methods[].idstring
contacts[].methods[].contactIdstring
contacts[].methods[].kindenumOne of PHONE, EMAIL.
contacts[].methods[].labelenumOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
contacts[].methods[].valuestringThe phone number or email address.
contacts[].methods[].isPrimarybooleanThe contact's main phone or email.
contacts[].methods[].smsConsentenumOK to text this phone (DENIED after the number replied STOP). One of UNKNOWN, GRANTED, DENIED.
contacts[].methods[].sortOrderinteger

All customers that are not archived, for pickers

GET /organizations/{organizationId}/customers/options

Every customer that is not archived, as id and display name only, for pickers and to find a customer's id by name. Read-only.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolcustomers_options (toolset customers)

Example

curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/options" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringCustomer id.
namestring
addressstring or null
citystring or null
doNotServiceboolean
doNotServiceReasonstring or null
creditLimitCentsinteger or null
taxExemptboolean
paymentTermsenumInvoice due date rule; CUSTOM uses paymentTermsDays. One of DUE_ON_RECEIPT, NET_7, NET_15, NET_30, NET_45, NET_60, CUSTOM.
paymentTermsDaysinteger or null
balanceCentsintegerOpen balance: due on SENT/OVERDUE invoices less unapplied deposits; negative = in credit, in integer cents.
lifetimeValueCentsintegerEvery payment collected, net of refunds, tips excluded, in integer cents.
overCreditLimitbooleanThe balance is above creditLimitCents.

Get a customer

GET /organizations/{organizationId}/customers/{customerId}

One customer with contacts, current and past properties (their addresses / ship-to locations), open balance (balanceCents, negative = in credit) and lifetime value. Quotes, invoices and requests have their own list calls filtered by customer. Read-only.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolcustomers_get (toolset customers, in the default set)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Example

curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
idstringCustomer id.
organizationIdstring
typeenumOne of RESIDENTIAL, COMMERCIAL.
titlestring or null
firstNamestring or null
lastNamestring or null
companyNamestring or null
namestringDisplay name, derived from the person or company name.
statusenumLEAD until the first sale, then ACTIVE; ARCHIVED customers leave the lists. One of LEAD, ACTIVE, INACTIVE, ARCHIVED.
emailstring or nullThe primary contact's main email.
phonestring or nullThe primary contact's main phone.
addressstring or nullBilling address (street).
address2string or null
citystring or null
statestring or null
zipstring or null
countrystring or null
leadSourceIdstring or nullFrom GET /lead-sources.
tagsarray of string
paymentTermsenumInvoice due date rule; CUSTOM uses paymentTermsDays. One of DUE_ON_RECEIPT, NET_7, NET_15, NET_30, NET_45, NET_60, CUSTOM.
paymentTermsDaysinteger or nullDays to pay, for CUSTOM terms.
taxExemptbooleanInvoices and quotes carry no tax.
taxExemptIdstring or null
creditLimitCentsinteger or nullCredit limit in integer cents; null = none.
doNotServicebooleanQuote and invoice screens warn before new work is sold.
doNotServiceReasonstring or null
allowEmailboolean
allowSmsboolean
allowMarketingboolean
notesstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields).
createdAtstring (date-time)
updatedAtstring (date-time)
contactsarray of objectContacts, primary first.
contacts[].idstringContact id.
contacts[].customerIdstring
contacts[].firstNamestring or null
contacts[].lastNamestring or null
contacts[].jobTitlestring or null
contacts[].rolesarray of enumWhat the contact is for; the primary contact has PRIMARY.
contacts[].isPrimarybooleanThe primary contact; its main email and phone mirror onto the customer.
contacts[].notesstring or null
contacts[].createdAtstring (date-time)
contacts[].updatedAtstring (date-time)
contacts[].methodsarray of objectPhones and emails, primary first.
contacts[].methods[].idstring
contacts[].methods[].contactIdstring
contacts[].methods[].kindenumOne of PHONE, EMAIL.
contacts[].methods[].labelenumOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
contacts[].methods[].valuestringThe phone number or email address.
contacts[].methods[].isPrimarybooleanThe contact's main phone or email.
contacts[].methods[].smsConsentenumOK to text this phone (DENIED after the number replied STOP). One of UNKNOWN, GRANTED, DENIED.
contacts[].methods[].sortOrderinteger
leadSourceobject or null
leadSource.idstring
leadSource.namestring
occupanciesarray of objectCurrent and past properties (current first), with the property.
occupancies[].idstringOccupancy id (for PATCH …/occupancies/{occupancyId}).
occupancies[].propertyIdstring
occupancies[].customerIdstring
occupancies[].roleenumOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
occupancies[].isPrimarybooleanThe property's primary current occupant.
occupancies[].startedOnstringFirst day of the link, YYYY-MM-DD.
occupancies[].endedOnstring or nullLast day, YYYY-MM-DD; null = current.
occupancies[].createdAtstring (date-time)
occupancies[].propertyobject
occupancies[].property.idstringProperty id.
occupancies[].property.organizationIdstring
occupancies[].property.namestring or null
occupancies[].property.addressstring or null
occupancies[].property.address2string or null
occupancies[].property.citystring or null
occupancies[].property.countystring or nullCounty, for tax rules that name one.
occupancies[].property.statestring or null
occupancies[].property.zipstring or null
occupancies[].property.countrystring or null
occupancies[].property.propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
occupancies[].property.contactNamestring or nullWho receives deliveries at this address.
occupancies[].property.contactPhonestring or null
occupancies[].property.contactEmailstring or null
occupancies[].property.timezonestringIANA timezone of the property.
occupancies[].property.accessInstructionsstring or nullDelivery or drop-off instructions for this address.
occupancies[].property.tagsarray of string
occupancies[].property.taxRatenumber or nullTax rate in percent for sales shipped here, overriding the tax rules; null = the business's tax rules for the address.
occupancies[].property.customFieldsanyCustom field values by key (definitions: GET /custom-fields).
occupancies[].property.createdAtstring (date-time)
occupancies[].property.updatedAtstring (date-time)
balanceCentsintegerOpen balance: due on SENT/OVERDUE invoices less unapplied deposits; negative = in credit, in integer cents.
lifetimeValueCentsintegerEvery payment collected, net of refunds, tips excluded, in integer cents.
overCreditLimitbooleanThe balance is above creditLimitCents.

Update a customer

PATCH /organizations/{organizationId}/customers/{customerId}

Changes the fields sent (status, names, billing terms, tax exemption, tags, custom fields …). Email and phone mirror the primary contact; change contacts with the /contacts calls. Returns the customer.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolcustomers_update (toolset customers, in the default set)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Request body

FieldTypeRequiredDescription
typeenumNoOne of RESIDENTIAL, COMMERCIAL.
titlestring or nullNo
firstNamestring or nullNo
lastNamestring or nullNo
companyNamestring or nullNo
namestringNo
statusenumNoOne of LEAD, ACTIVE, INACTIVE, ARCHIVED.
emailempty string or string (email) or nullNo
phonestring or nullNo
addressstring or nullNo
address2string or nullNo
citystring or nullNo
statestring or nullNo
zipstring or nullNo
countrystring or nullNo
leadSourceIdstring or nullNo
tagsarray of stringNoUp to 100 items.
paymentTermsenumNoOne of DUE_ON_RECEIPT, NET_7, NET_15, NET_30, NET_45, NET_60, CUSTOM.
paymentTermsDaysinteger or nullNo0–3650.
taxExemptbooleanNo
taxExemptIdstring or nullNo
creditLimitCentsinteger or nullNo0–1000000000.
doNotServicebooleanNo
doNotServiceReasonstring or nullNo
allowEmailbooleanNo
allowSmsbooleanNo
allowMarketingbooleanNo
notesstring or nullNo
customFieldsobjectNo

Example

curl -X PATCH "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"RESIDENTIAL","title":"string","firstName":"string"}'

Response

200: the answer's fields
FieldTypeDescription
idstringCustomer id.
organizationIdstring
typeenumOne of RESIDENTIAL, COMMERCIAL.
titlestring or null
firstNamestring or null
lastNamestring or null
companyNamestring or null
namestringDisplay name, derived from the person or company name.
statusenumLEAD until the first sale, then ACTIVE; ARCHIVED customers leave the lists. One of LEAD, ACTIVE, INACTIVE, ARCHIVED.
emailstring or nullThe primary contact's main email.
phonestring or nullThe primary contact's main phone.
addressstring or nullBilling address (street).
address2string or null
citystring or null
statestring or null
zipstring or null
countrystring or null
leadSourceIdstring or nullFrom GET /lead-sources.
tagsarray of string
paymentTermsenumInvoice due date rule; CUSTOM uses paymentTermsDays. One of DUE_ON_RECEIPT, NET_7, NET_15, NET_30, NET_45, NET_60, CUSTOM.
paymentTermsDaysinteger or nullDays to pay, for CUSTOM terms.
taxExemptbooleanInvoices and quotes carry no tax.
taxExemptIdstring or null
creditLimitCentsinteger or nullCredit limit in integer cents; null = none.
doNotServicebooleanQuote and invoice screens warn before new work is sold.
doNotServiceReasonstring or null
allowEmailboolean
allowSmsboolean
allowMarketingboolean
notesstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields).
createdAtstring (date-time)
updatedAtstring (date-time)
contactsarray of object
contacts[].idstringContact id.
contacts[].customerIdstring
contacts[].firstNamestring or null
contacts[].lastNamestring or null
contacts[].jobTitlestring or null
contacts[].rolesarray of enumWhat the contact is for; the primary contact has PRIMARY.
contacts[].isPrimarybooleanThe primary contact; its main email and phone mirror onto the customer.
contacts[].notesstring or null
contacts[].createdAtstring (date-time)
contacts[].updatedAtstring (date-time)
contacts[].methodsarray of objectPhones and emails, primary first.
contacts[].methods[].idstring
contacts[].methods[].contactIdstring
contacts[].methods[].kindenumOne of PHONE, EMAIL.
contacts[].methods[].labelenumOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
contacts[].methods[].valuestringThe phone number or email address.
contacts[].methods[].isPrimarybooleanThe contact's main phone or email.
contacts[].methods[].smsConsentenumOK to text this phone (DENIED after the number replied STOP). One of UNKNOWN, GRANTED, DENIED.
contacts[].methods[].sortOrderinteger

Delete a customer

DELETE /organizations/{organizationId}/customers/{customerId}

Destructive: deletes the customer with their contacts, notes, quotes, invoices and payments. Refused (409) while the customer has or had a property (end or transfer it, or archive the customer with PATCH status: ARCHIVED, which keeps everything).

Permissioncustomers.delete (Owner, Admin)
Risksensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolcustomers_delete (toolset customers)
ApprovalOver MCP, this tool always waits for your approval in SKUFlow. See Approvals.

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Example

curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

List a customer's contacts

GET /organizations/{organizationId}/customers/{customerId}/contacts

The customer's contacts with their roles (primary, billing, site …) and phones and emails. Read-only.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolcontacts_list (toolset customers)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Example

curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/contacts" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringContact id.
customerIdstring
firstNamestring or null
lastNamestring or null
jobTitlestring or null
rolesarray of enumWhat the contact is for; the primary contact has PRIMARY.
isPrimarybooleanThe primary contact; its main email and phone mirror onto the customer.
notesstring or null
createdAtstring (date-time)
updatedAtstring (date-time)
methodsarray of objectPhones and emails, primary first.
methods[].idstring
methods[].contactIdstring
methods[].kindenumOne of PHONE, EMAIL.
methods[].labelenumOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
methods[].valuestringThe phone number or email address.
methods[].isPrimarybooleanThe contact's main phone or email.
methods[].smsConsentenumOK to text this phone (DENIED after the number replied STOP). One of UNKNOWN, GRANTED, DENIED.
methods[].sortOrderinteger

Add a contact

POST /organizations/{organizationId}/customers/{customerId}/contacts

Adds a contact to the customer with roles and phone/email methods. The first contact, or one marked primary, becomes the primary contact and its email/phone mirror onto the customer. Returns the contact.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolcontacts_create (toolset customers, in the default set)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Request body

FieldTypeRequiredDescription
firstNamestring or nullNo
lastNamestring or nullNo
jobTitlestring or nullNo
rolesarray of enumNoUp to 7 items.
isPrimarybooleanNo
notesstring or nullNo
methodsarray of objectNoUp to 50 items.
methods[].kindenumYesOne of PHONE, EMAIL.
methods[].labelenumNoOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
methods[].valuestringYesUp to 500 characters.
methods[].isPrimarybooleanNo
methods[].smsConsentenumNoOne of UNKNOWN, GRANTED, DENIED.

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/contacts" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"firstName":"string","lastName":"string","jobTitle":"string"}'

Response

201: the answer's fields
FieldTypeDescription
idstringContact id.
customerIdstring
firstNamestring or null
lastNamestring or null
jobTitlestring or null
rolesarray of enumWhat the contact is for; the primary contact has PRIMARY.
isPrimarybooleanThe primary contact; its main email and phone mirror onto the customer.
notesstring or null
createdAtstring (date-time)
updatedAtstring (date-time)
methodsarray of objectPhones and emails, primary first.
methods[].idstring
methods[].contactIdstring
methods[].kindenumOne of PHONE, EMAIL.
methods[].labelenumOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
methods[].valuestringThe phone number or email address.
methods[].isPrimarybooleanThe contact's main phone or email.
methods[].smsConsentenumOK to text this phone (DENIED after the number replied STOP). One of UNKNOWN, GRANTED, DENIED.
methods[].sortOrderinteger

Update a contact

PATCH /organizations/{organizationId}/customers/{customerId}/contacts/{contactId}

Changes the fields sent. methods, when given, replaces the contact's phones and emails (send the full list). Returns the contact.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolcontacts_update (toolset customers)

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes
contactIdpathstringYes

Request body

FieldTypeRequiredDescription
firstNamestring or nullNo
lastNamestring or nullNo
jobTitlestring or nullNo
rolesarray of enumNoUp to 7 items.
isPrimarybooleanNo
notesstring or nullNo
methodsarray of objectNoUp to 50 items.
methods[].kindenumYesOne of PHONE, EMAIL.
methods[].labelenumNoOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
methods[].valuestringYesUp to 500 characters.
methods[].isPrimarybooleanNo
methods[].smsConsentenumNoOne of UNKNOWN, GRANTED, DENIED.

Example

curl -X PATCH "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/contacts/{contactId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"firstName":"string","lastName":"string","jobTitle":"string"}'

Response

200: the answer's fields
FieldTypeDescription
idstringContact id.
customerIdstring
firstNamestring or null
lastNamestring or null
jobTitlestring or null
rolesarray of enumWhat the contact is for; the primary contact has PRIMARY.
isPrimarybooleanThe primary contact; its main email and phone mirror onto the customer.
notesstring or null
createdAtstring (date-time)
updatedAtstring (date-time)
methodsarray of objectPhones and emails, primary first.
methods[].idstring
methods[].contactIdstring
methods[].kindenumOne of PHONE, EMAIL.
methods[].labelenumOne of MAIN, MOBILE, WORK, HOME, FAX, OTHER.
methods[].valuestringThe phone number or email address.
methods[].isPrimarybooleanThe contact's main phone or email.
methods[].smsConsentenumOK to text this phone (DENIED after the number replied STOP). One of UNKNOWN, GRANTED, DENIED.
methods[].sortOrderinteger

Delete a contact

DELETE /organizations/{organizationId}/customers/{customerId}/contacts/{contactId}

Destructive: deletes the contact and its phones and emails. Deleting the primary contact promotes the next one.

Permissioncustomers.write (Owner, Admin, Staff)
Risksensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolcontacts_delete (toolset customers)
ApprovalOver MCP, this tool always waits for your approval in SKUFlow. See Approvals.

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes
contactIdpathstringYes

Example

curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/contacts/{contactId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

List notes on a customer or property

GET /organizations/{organizationId}/{ownerType}/{ownerId}/notes

Internal notes on a customer or property (ownerType is customers or properties, ownerId its id). Pinned first, then newest first. Read-only.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolrecordNotes_list (toolset customers)

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes

Example

curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/notes" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringNote id.
customerIdstring or null
propertyIdstring or null
contentstringInternal note text; never shown to the customer.
pinnedboolean
authorUserIdstring or null
createdAtstring (date-time)

Add a note

POST /organizations/{organizationId}/{ownerType}/{ownerId}/notes

Adds an internal note (never shown to the customer) to a customer or property, authored by the caller. Returns the note.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolrecordNotes_create (toolset customers, in the default set)

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes

Request body

FieldTypeRequiredDescription
contentstringYes
pinnedbooleanNo

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/notes" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"string"}'

Response

201: the answer's fields
FieldTypeDescription
idstringNote id.
customerIdstring or null
propertyIdstring or null
contentstringInternal note text; never shown to the customer.
pinnedboolean
authorUserIdstring or null
createdAtstring (date-time)

Edit or pin a note

PATCH /organizations/{organizationId}/{ownerType}/{ownerId}/notes/{noteId}

Changes a note's text and/or pins it to the top. Note ids come from the list call.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolrecordNotes_update (toolset customers)

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes
noteIdpathstringYes

Request body

FieldTypeRequiredDescription
contentstringNo
pinnedbooleanNo

Example

curl -X PATCH "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/notes/{noteId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"string","pinned":true}'

Response

200: the answer's fields
FieldTypeDescription
idstringNote id.
customerIdstring or null
propertyIdstring or null
contentstringInternal note text; never shown to the customer.
pinnedboolean
authorUserIdstring or null
createdAtstring (date-time)

Delete a note

DELETE /organizations/{organizationId}/{ownerType}/{ownerId}/notes/{noteId}

Destructive: deletes the note from the customer or property. Cannot be undone.

Permissioncustomers.write (Owner, Admin, Staff)
Risksensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolrecordNotes_delete (toolset customers)
ApprovalOver MCP, this tool always waits for your approval in SKUFlow. See Approvals.

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes
noteIdpathstringYes

Example

curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/notes/{noteId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

List files on a customer or property

GET /organizations/{organizationId}/{ownerType}/{ownerId}/attachments

Files on a customer or property, each with a download URL valid for 10 minutes. Read-only.

Permissioncustomers.read (Owner, Admin, Staff, Member)
Riskread, OAuth scope skuflow.read. Read: reads only.
MCP toolattachments_list (toolset customers)

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes

Example

curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/attachments" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringAttachment id.
organizationIdstring
customerIdstring or null
propertyIdstring or null
tagenum or nullOne of BEFORE, AFTER, GENERAL, ISSUE, SIGNATURE.
fileNamestring
contentTypestring
sizeBytesinteger
uploadedByUserIdstring or null
uploadedAtstring (date-time) or nullSet once the upload is confirmed; null before.
createdAtstring (date-time)
downloadUrlstringDownload URL, valid for 10 minutes.

Start a file upload

POST /organizations/{organizationId}/{ownerType}/{ownerId}/attachments

Step 1 of 2 of attaching a file: returns uploadUrl; PUT the file there (with the same Content-Type) within 5 minutes, then call POST …/attachments/{attachmentId}/confirm. Unconfirmed uploads are not listed.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolattachments_createUpload (toolset customers)

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes

Request body

FieldTypeRequiredDescription
fileNamestringYesUp to 500 characters.
contentTypestringYesUp to 200 characters.
sizeBytesintegerYes

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/attachments" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fileName":"string","contentType":"string","sizeBytes":1}'

Response

201: the answer's fields
FieldTypeDescription
attachmentobject
attachment.idstringAttachment id.
attachment.organizationIdstring
attachment.customerIdstring or null
attachment.propertyIdstring or null
attachment.tagenum or nullOne of BEFORE, AFTER, GENERAL, ISSUE, SIGNATURE.
attachment.fileNamestring
attachment.contentTypestring
attachment.sizeBytesinteger
attachment.uploadedByUserIdstring or null
attachment.uploadedAtstring (date-time) or nullSet once the upload is confirmed; null before.
attachment.createdAtstring (date-time)
uploadUrlstringPUT the file here (same Content-Type) within 5 minutes, then confirm.

Confirm a finished upload

POST /organizations/{organizationId}/{ownerType}/{ownerId}/attachments/{attachmentId}/confirm

Step 2 of 2: marks the uploaded file as present so it is listed. Call after the PUT to uploadUrl from POST …/attachments succeeded.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolattachments_confirm (toolset customers)

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes
attachmentIdpathstringYes

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/attachments/{attachmentId}/confirm" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
idstringAttachment id.
organizationIdstring
customerIdstring or null
propertyIdstring or null
tagenum or nullOne of BEFORE, AFTER, GENERAL, ISSUE, SIGNATURE.
fileNamestring
contentTypestring
sizeBytesinteger
uploadedByUserIdstring or null
uploadedAtstring (date-time) or nullSet once the upload is confirmed; null before.
createdAtstring (date-time)

Delete a file

DELETE /organizations/{organizationId}/{ownerType}/{ownerId}/attachments/{attachmentId}

Destructive: deletes the file and its stored object.

Permissioncustomers.write (Owner, Admin, Staff)
Risksensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolattachments_delete (toolset customers)
ApprovalOver MCP, this tool always waits for your approval in SKUFlow. See Approvals.

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes
attachmentIdpathstringYes

Example

curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/attachments/{attachmentId}" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

Attach a file (content in the request)

POST /organizations/{organizationId}/{ownerType}/{ownerId}/attachments/content

Attaches a file to a customer or property in one call (ownerType customers or properties, ownerId its id): send contentBase64 or a public sourceUrl (up to 10 MB; any type). The file is stored privately and listed with the record's files (GET …/attachments, with a 10-minute download URL). The browser uploads with POST …/attachments and confirm instead. Returns the file.

Permissioncustomers.write (Owner, Admin, Staff)
Riskwrite, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolattachments_upload (toolset customers, in the default set)

Parameters

NameInTypeRequiredDescription
ownerTypepathenumYesOne of customers, properties.
ownerIdpathstringYes

Request body

FieldTypeRequiredDescription
fileNamestringNoThe file's name, e.g. receipt.jpg (default: from the URL, else 'file'). Up to 500 characters.
contentTypestringNoMIME type, e.g. image/jpeg or application/pdf. Optional: taken from a data: URL, the URL's answer or the file's first bytes. Up to 200 characters.
contentBase64stringNoThe file's bytes as base64 (a data: URL is accepted too). Up to 10 MB. Give this or sourceUrl.
sourceUrlstring (uri)NoA public http(s) URL SKUFlow downloads the file from (up to 10 MB, 20 s, 3 redirects; private and internal addresses are refused). Give this or contentBase64. Up to 2000 characters.

Example

curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/{ownerType}/{ownerId}/attachments/content" \
  -H "Authorization: Bearer $SKUFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"fileName":"string","contentType":"string","contentBase64":"string"}'

Response

201: the answer's fields
FieldTypeDescription
idstringThe attachment id.
fileNamestring
contentTypestring
sizeBytesinteger
uploadedAtstring (date-time) or null
createdAtstring (date-time)

On this page