Kanorio

API 參考

Contacts

Management API: GET /sites/{id}/contacts, POST /sites/{id}/contacts, GET /sites/{id}/contacts/{contactId}, …

這頁只有英文版。API 參考、Webhook 事件與變更紀錄維持英文,和程式碼裡的欄位名稱、錯誤碼一致。
Base URL https://app.kanorio.com/api/v1ErrorsPagination

List contacts

GET/sites/{id}/contacts
betacustomers:viewdefault (120/minute per token)

List contacts with email marketing status, tags and purchase summary. Filter by status, source, buyers only, or search on email/name/phone; sort by RECENT, SPENT or LAST_ORDER. Errors: FORBIDDEN, INVALID_CURSOR.

Parameters

  • idstring · pathrequired

    Website id. Get it from sites.list or from sites.create.

  • limitinteger · query

    Maximum number of items to return, 1–100. Defaults to 20.

  • cursorstring · query

    Opaque cursor from the previous page's nextCursor. Omit for the first page.

  • searchstring · query
  • status"ALL" | "NEVER_SUBSCRIBED" | "PENDING" | "SUBSCRIBED" | "UNSUBSCRIBED" | "BOUNCED" | "COMPLAINED" · query
  • source"ALL" | "CHECKOUT" | "ORDER" | "IMPORT" | "FORM" | "MANUAL" | "ADMIN" · query
  • buyer"ALL" | "BUYERS" · query

    BUYERS = has at least one paid order.

  • sort"RECENT" | "SPENT" | "LAST_ORDER" · query

Response 200

  • dataobject[]required
  • data[].idstringrequired
  • data[].emailstring | nullrequired
  • data[].phonestring | nullrequired

    E.164.

  • data[].namestring | nullrequired
  • data[].emailStatusstringrequired

    Email marketing consent: NEVER_SUBSCRIBED, PENDING, SUBSCRIBED, UNSUBSCRIBED, BOUNCED, COMPLAINED.

  • data[].sourcestringrequired
  • data[].createdAtstringrequired
  • data[].tagsstring[]required
  • data[].customerobject | nullrequired

    EC purchase summary; null when the contact never bought anything.

  • data[].customer.ordersCountintegerrequired
  • data[].customer.totalSpentintegerrequired

    Minor units in the website currency (orders in other currencies are not included).

  • data[].customer.lastOrderAtstring | nullrequired
  • hasMorebooleanrequired

    True when another page exists; pass nextCursor to fetch it.

  • nextCursorstring | nullrequired

    Cursor for the next page, or null on the last page.

Errors

  • FORBIDDEN 403
  • INVALID_CURSOR 400

MCP tool contacts_list

curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/contacts" \
  -H "Authorization: Bearer $KANORIO_TOKEN"
Response
{
  "data": [
    {
      "id": "contact_example01",
      "email": "customer@example.com",
      "phone": "+886912345678",
      "name": "Alex Chen",
      "emailStatus": "SUBSCRIBED",
      "source": "FORM",
      "createdAt": "2026-10-01T02:30:00.000Z",
      "tags": [
        "VIP",
        "cake-order"
      ],
      "accessStatus": "ACTIVE",
      "externalId": null,
      "externalIdOrigin": null,
      "metadata": {},
      "customer": {
        "ordersCount": 3,
        "totalSpent": 2640,
        "lastOrderAt": "2026-10-06T08:00:00.000Z"
      }
    }
  ],
  "hasMore": false,
  "nextCursor": null
}

Add a contact

POST/sites/{id}/contacts
betacustomers:managedefault (120/minute per token)

Add one contact by email (source MANUAL). Only set marketingConsent=true when the person has explicitly agreed to receive marketing email; otherwise the contact is created without consent. externalId and metadata let you link the contact to your own system. Errors: FORBIDDEN, VALIDATION, DUPLICATE (email already exists), SUPPRESSED (address is blocked), INVALID_EMAIL, INVALID_PHONE, EXTERNAL_ID_IN_USE.

Parameters

  • idstring · pathrequired

    Website id. Get it from sites.list or from sites.create.

Request body

  • emailstringrequired
  • namestring
  • phonestring

    Any common format; normalized to E.164 using the store's country.

  • tagsstring[]
  • notestring
  • marketingConsentboolean

    Defaults to false.

  • externalIdstring

    Your system's id for this person (POS, ERP, CRM). Unique per site and set once; it is never used to match or merge contacts.

  • externalIdOriginstring

    Name of the system the externalId comes from, e.g. "shopify", "hubspot".

  • metadataobject

    Integration fields to set on the new contact.

Response 201

  • contactIdstringrequired

Errors

  • FORBIDDEN 403
  • VALIDATION 400
  • DUPLICATE 409 · email already exists
  • SUPPRESSED 422 · address is blocked
  • INVALID_EMAIL 400
  • INVALID_PHONE 400
  • EXTERNAL_ID_IN_USE 422

MCP tool contacts_add

curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/contacts" \
  -H "Authorization: Bearer $KANORIO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"customer@example.com","name":"Alex Chen","tags":["cake-order"],"marketingConsent":false}'
Response
{
  "contactId": "contact_example01"
}

Retrieve a contact

GET/sites/{id}/contacts/{contactId}
betacustomers:viewdefault (120/minute per token)

Get one contact by contactId or by externalId (your system's id) with consent state, sign-in status, note, custom profile attributes, metadata, purchase summary with recent orders, and the last 50 timeline events/messages. Errors: FORBIDDEN, VALIDATION, CONTACT_NOT_FOUND.

Parameters

  • idstring · pathrequired

    Website id. Get it from sites.list or from sites.create.

  • contactIdstring · pathrequired

    Contact id. Get it from contacts.list.

  • externalIdstring · query

    Look the contact up by your system's id instead of contactId.

Response 200

  • idstringrequired
  • emailstring | nullrequired
  • phonestring | nullrequired

    E.164.

  • namestring | nullrequired
  • emailStatusstringrequired

    Email marketing consent: NEVER_SUBSCRIBED, PENDING, SUBSCRIBED, UNSUBSCRIBED, BOUNCED, COMPLAINED.

  • sourcestringrequired
  • createdAtstringrequired
  • tagsstring[]required
  • customerobject | nullrequired
  • customer.idstringrequired
  • customer.ordersCountintegerrequired
  • customer.totalSpentintegerrequired
  • customer.lastOrderAtstring | nullrequired
  • customer.acceptsMarketingbooleanrequired
  • customer.countrystring | nullrequired
  • customer.recentOrdersobject[]required
  • customer.recentOrders[].idstringrequired
  • customer.recentOrders[].orderNumberinteger | nullrequired
  • customer.recentOrders[].statusstringrequired
  • customer.recentOrders[].paidAmountintegerrequired
  • customer.recentOrders[].currencystringrequired
  • customer.recentOrders[].createdAtstringrequired
  • localestring | nullrequired
  • emailConsentAtstring | nullrequired
  • emailUnsubscribedAtstring | nullrequired
  • notestringrequired
  • accessStatus"ACTIVE" | "BLOCKED" | "PENDING"required

    Sign-in status. BLOCKED: the person cannot sign in to the account portal; orders and emails are unaffected.

  • externalIdstring | nullrequired

    Your system's id for this person; null when none was set.

  • externalIdOriginstring | nullrequired

    Which system the externalId comes from.

  • metadataobjectrequired

    Integration fields (flat key/value, up to 50 keys).

  • suppressedbooleanrequired

    On the tenant suppression list (bounce/complaint/manual block).

  • profileobject[]required

    Custom attributes collected via forms.

  • profile[].keystringrequired
  • profile[].labelstringrequired
  • profile[].valuestringrequired
  • consentLogsobject[]required
  • consentLogs[].idstringrequired
  • consentLogs[].channelstringrequired
  • consentLogs[].actionstringrequired
  • consentLogs[].sourcestringrequired
  • consentLogs[].createdAtstringrequired
  • eventsobject[]required
  • events[].idstringrequired
  • events[].typestringrequired
  • events[].occurredAtstringrequired
  • events[].payloadanyrequired
  • messagesobject[]required
  • messages[].idstringrequired
  • messages[].channelstringrequired
  • messages[].kindstringrequired
  • messages[].typestringrequired
  • messages[].statusstringrequired
  • messages[].atstringrequired

Errors

  • FORBIDDEN 403
  • VALIDATION 400
  • CONTACT_NOT_FOUND 404

MCP tool contacts_get

curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/contacts/{contactId}" \
  -H "Authorization: Bearer $KANORIO_TOKEN"
Response
{
  "id": "contact_example01",
  "email": "customer@example.com",
  "phone": "+886912345678",
  "name": "Alex Chen",
  "emailStatus": "SUBSCRIBED",
  "source": "FORM",
  "createdAt": "2026-10-01T02:30:00.000Z",
  "tags": [
    "VIP",
    "cake-order"
  ],
  "accessStatus": "ACTIVE",
  "externalId": null,
  "externalIdOrigin": null,
  "metadata": {},
  "customer": {
    "id": "customer_example01",
    "ordersCount": 3,
    "totalSpent": 2640,
    "lastOrderAt": "2026-10-06T08:00:00.000Z",
    "acceptsMarketing": true,
    "country": "TW",
    "recentOrders": [
      {
        "id": "order_example01",
        "orderNumber": 1024,
        "status": "PAID",
        "paidAmount": 980,
        "currency": "TWD",
        "createdAt": "2026-10-06T08:00:00.000Z"
      }
    ]
  },
  "locale": "zh-Hant",
  "emailConsentAt": "2026-10-01T02:30:00.000Z",
  "emailUnsubscribedAt": null,
  "note": "Prefers less sugar.",
  "suppressed": false,
  "profile": [
    {
      "key": "birthday",
      "label": "Birthday",
      "value": "10-20"
    }
  ],
  "consentLogs": [
    {
      "id": "consent_example01",
      "channel": "EMAIL",
      "action": "SUBSCRIBE",
      "source": "FORM",
      "createdAt": "2026-10-01T02:30:00.000Z"
    }
  ],
  "events": [
    {
      "id": "evt_example01",
      "type": "form.submitted",
      "occurredAt": "2026-10-01T02:30:00.000Z",
      "payload": {
        "formId": "form_example01"
      }
    }
  ],
  "messages": [
    {
      "id": "msg_example01",
      "channel": "EMAIL",
      "kind": "CAMPAIGN",
      "type": "campaign",
      "status": "DELIVERED",
      "at": "2026-10-06T08:00:00.000Z"
    }
  ]
}

Update a contact

PATCH/sites/{id}/contacts/{contactId}
betacustomers:managedefault (120/minute per token)

Update a contact's name, tags, owner note, externalId and/or metadata (provide at least one; the others keep their current value). Tags are trimmed, de-duplicated, max 20 × 50 chars. externalId can be set once. metadata is merged: keys you send are set, null deletes a key. Email and phone are identities and are not editable. Errors: FORBIDDEN, VALIDATION, CONTACT_NOT_FOUND, EXTERNAL_ID_ALREADY_SET, EXTERNAL_ID_IN_USE.

Parameters

  • idstring · pathrequired

    Website id. Get it from sites.list or from sites.create.

  • contactIdstring · pathrequired

    Contact id. Get it from contacts.list.

Request body

  • namestring

    Display name: printed on certificates and used in email greetings. Empty string clears it (the email address is shown instead). Email and phone are identities and cannot be changed here.

  • tagsstring[]
  • notestring
  • externalIdstring

    Set once; re-sending the same value is a no-op, a different value fails with EXTERNAL_ID_ALREADY_SET.

  • externalIdOriginstring

    Name of the system the externalId comes from, e.g. "shopify", "hubspot".

  • metadataobject

    Integration fields. Keys you send are set, a null value deletes that key, keys you omit are kept. Up to 50 keys / 16 KB after merging.

Response 200

  • contactIdstringrequired
  • namestring | nullrequired
  • tagsstring[]required
  • notestringrequired
  • externalIdstring | nullrequired
  • metadataobjectrequired

Errors

  • FORBIDDEN 403
  • VALIDATION 400
  • CONTACT_NOT_FOUND 404
  • EXTERNAL_ID_ALREADY_SET 422
  • EXTERNAL_ID_IN_USE 422

MCP tool contacts_update

curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/contacts/{contactId}" \
  -H "Authorization: Bearer $KANORIO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Alex Chen","tags":["VIP","cake-order"],"note":"Prefers less sugar."}'
Response
{
  "contactId": "contact_example01",
  "name": "Alex Chen",
  "tags": [
    "VIP",
    "cake-order"
  ],
  "note": "Prefers less sugar.",
  "externalId": null,
  "metadata": {}
}

Update tags note

PATCH/sites/{id}/contacts/{contactId}/tags-note
Deprecated, sunset 2027-04-30customers:managedefault (120/minute per token)

Use contacts.update instead.

[Deprecated, removed after 2027-04-30; use contacts.update instead. contacts.update covers the same fields and can also set the contact's name, which certificates print and emails use as the greeting.] Deprecated alias of contacts.update (also accepts name, externalId and metadata). Errors: FORBIDDEN, VALIDATION, CONTACT_NOT_FOUND, EXTERNAL_ID_ALREADY_SET, EXTERNAL_ID_IN_USE.

Parameters

  • idstring · pathrequired

    Website id. Get it from sites.list or from sites.create.

  • contactIdstring · pathrequired

    Contact id. Get it from contacts.list.

Request body

  • namestring

    Display name: printed on certificates and used in email greetings. Empty string clears it (the email address is shown instead). Email and phone are identities and cannot be changed here.

  • tagsstring[]
  • notestring
  • externalIdstring

    Set once; re-sending the same value is a no-op, a different value fails with EXTERNAL_ID_ALREADY_SET.

  • externalIdOriginstring

    Name of the system the externalId comes from, e.g. "shopify", "hubspot".

  • metadataobject

    Integration fields. Keys you send are set, a null value deletes that key, keys you omit are kept. Up to 50 keys / 16 KB after merging.

Response 200

  • contactIdstringrequired
  • namestring | nullrequired
  • tagsstring[]required
  • notestringrequired
  • externalIdstring | nullrequired
  • metadataobjectrequired

Errors

  • FORBIDDEN 403
  • VALIDATION 400
  • CONTACT_NOT_FOUND 404
  • EXTERNAL_ID_ALREADY_SET 422
  • EXTERNAL_ID_IN_USE 422

MCP tool contacts_update_tags_note

curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/contacts/{contactId}/tags-note" \
  -H "Authorization: Bearer $KANORIO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tags":["VIP","cake-order"],"note":"Prefers less sugar."}'
Response
{
  "contactId": "contact_example01",
  "name": "Alex Chen",
  "tags": [
    "VIP",
    "cake-order"
  ],
  "note": "Prefers less sugar.",
  "externalId": null,
  "metadata": {}
}