Skip to main content

Keap integration

Run small-business CRM, sales pipeline, tags, orders, and campaign automation across your clients' Keap accounts.

What it does

The Keap integration lets your agency operate a client's small-business CRM without leaving TaskJuice. Connect a client's Keap (formerly Infusionsoft) account once and you can create and look up contacts, move opportunities through the pipeline, apply and remove tags, raise orders and record payments, manage subscriptions, and start contacts into campaign sequences.

Actions target the Keap REST v2 API, the version Keap actively develops. Two surfaces stay on REST v1 because v2 has no equivalent: uploading a file, and the REST Hooks that power every webhook trigger.

Connect a Keap account

  1. Open your workspace in TaskJuice and navigate to Connections.
  2. Choose Keap and click Connect.
  3. Sign in to Keap as a user with permission to install third-party applications.
  4. Keap issues a single OAuth scope (full) covering every REST endpoint the integration uses, so there is nothing to pick.
  5. TaskJuice returns to the workspace with the connection ready to use.

To revoke access, the account owner opens Keap, navigates to Admin then Settings, and removes the TaskJuice application. The grant flow is documented in the Keap OAuth setup guide.

Triggers

TaskJuice registers and tears down the underlying Keap REST Hook for you when you publish or unpublish a workflow. You do not create the subscription by hand.

  • keap/contact-added triggers when a new contact is created in Keap (REST Hook contact.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the contact itself never arrives. Add a downstream Get Contact step on object_keys[0].id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/contact-updated triggers when a contact is updated in Keap (REST Hook contact.edit event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the contact itself never arrives. Add a downstream Get Contact step on object_keys[0].id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/tag-applied triggers when a tag is applied to a contact in Keap (REST Hook contactGroup.applied event). Deliveries for this event arrive on a 5-10 minute batching interval. THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the contact and tag itself never arrives. Keap ships no single-record Get action for this object, fetch object_keys[].apiUrl directly with an HTTP step using the same connection. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/tag-created triggers when a new tag is created in Keap (REST Hook contactGroup.add event). Distinct from a tag being applied to a contact. THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the tag itself never arrives. Keap ships no single-record Get action for this object, fetch object_keys[].apiUrl directly with an HTTP step using the same connection. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/opportunity-added triggers when a new sales opportunity is created in Keap (REST Hook opportunity.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the opportunity itself never arrives. Read it back with List Opportunities filtered on the id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/opportunity-stage-moved triggers when an opportunity moves to a different pipeline stage in Keap (REST Hook opportunity.stage_move event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the opportunity itself never arrives. Read it back with List Opportunities filtered on the id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/company-added triggers when a new company is created in Keap (REST Hook company.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the company itself never arrives. Read it back with List Companies filtered on the id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/note-added triggers when a new note is created in Keap (REST Hook note.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the note itself never arrives. Add a downstream Get Note step on object_keys[0].id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/task-added triggers when a new task is created in Keap (REST Hook task.add event). To watch tasks for a single assignee, add a downstream Filter on the fetched task's user.
  • keap/appointment-added triggers when a new appointment is created in Keap (REST Hook appointment.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the appointment itself never arrives. Keap ships no single-record Get action for this object, fetch object_keys[].apiUrl directly with an HTTP step using the same connection. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/invoice-added triggers when a new invoice is created in Keap (REST Hook invoice.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the invoice itself never arrives. Read it back with Get Order (Keap models invoices as orders) or List Orders (Find Invoice). Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/payment-added triggers when a payment is added to an invoice in Keap (REST Hook invoice.payment.add event). The delivery carries changed-object references only; fetch the payment to filter by payment type.
  • keap/order-added triggers when a new order is created in Keap (REST Hook order.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the order itself never arrives. Add a downstream Get Order step on object_keys[0].id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/subscription-added triggers when a new subscription is created in Keap (REST Hook subscription.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the subscription itself never arrives. Keap ships no single-record Get action for this object, fetch object_keys[].apiUrl directly with an HTTP step using the same connection. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.
  • keap/product-added triggers when a new product is created in Keap (REST Hook product.add event). THIS TRIGGER DELIVERS IDENTIFIERS, NOT THE RECORD: Keap posts { event_key, object_type, object_keys: [{ apiUrl, id, timestamp }] }, the product itself never arrives. Read it back with List Products filtered on the id. Keap batches, so object_keys can carry more than one id: Loop over it (type: 'array', arrayPath: 'object_keys') when a delivery may name several.

Keap does not sign hook deliveries. Each workflow receives its own tenant-scoped ingress URL, and TaskJuice rejects any delivery that does not present that URL's token.

Two surfaces have no Keap hook, so they poll instead. Each cycle emits one activation wrapping every newly seen record in items; add a Loop node downstream to process them one at a time.

  • keap/email-sent polls Keap's sent-email records (REST v2 GET /v2/emails, newest first) each cycle and emits one activation containing every email record not seen on a prior cycle, deduplicated by email id. Keap exposes no REST Hook for sent emails, so this trigger polls. Drop a Loop node downstream to process each email individually.
  • keap/file-added polls Keap's file box (REST v2 GET /v2/files, most recently updated first) each cycle and emits one activation containing the files it admits, deduplicated by file id. Only files created after the workflow is first published fire, judged by the file's own creation date, so renaming or replacing an older file does not fire it. Keap exposes no REST Hook for files, so this trigger polls. Drop a Loop node downstream to process each file individually.

Actions

  • keap/create-contact creates a contact in Keap (REST v2 POST /v2/contacts).
  • keap/upsert-contact creates a contact, or updates the existing one that matches on the chosen duplicate-handling fields (REST v2 POST /v2/contacts?duplicate_option=).
  • keap/update-contact updates named fields on a contact (REST v2 PATCH /v2/contacts/{id}). Only fields listed in Fields to Update are written.
  • keap/get-contact retrieves a single contact by ID (REST v2 GET /v2/contacts/{id}).
  • keap/list-contacts lists or searches contacts (REST v2 GET /v2/contacts). Use Filter to find a contact by email.
  • keap/delete-contact permanently deletes a contact (REST v2 DELETE /v2/contacts/{id}).
  • keap/get-contact-model retrieves the contact custom-field model, including every custom field ID and its options (REST v2 GET /v2/contacts/model).
  • keap/apply-tag applies a tag to one or more contacts (REST v2 POST /v2/tags/{tagId}/contacts:applyTags).
  • keap/remove-tag removes an applied tag from one or more contacts (REST v2 POST /v2/tags/{tagId}/contacts:removeTags).
  • keap/create-tag creates a tag (REST v2 POST /v2/tags).
  • keap/create-tag-category creates a tag category (REST v2 POST /v2/tags/categories).
  • keap/list-tags lists tags (REST v2 GET /v2/tags).
  • keap/list-tag-categories lists tag categories (REST v2 GET /v2/tags/categories).
  • keap/list-tagged-contacts lists every contact carrying a given tag (REST v2 GET /v2/tags/{tagId}/contacts).
  • keap/send-email sends an email to one or more contacts through Keap and records it on their timeline (REST v2 POST /v2/emails:send).
  • keap/create-email-record records an email that was sent outside Keap onto a contact timeline, without sending anything (REST v2 POST /v2/emails).
  • keap/create-note adds a note to a contact (REST v2 POST /v2/contacts/{contactId}/notes).
  • keap/get-note retrieves a note on a contact (REST v2 GET /v2/contacts/{contactId}/notes/{noteId}).
  • keap/update-note updates named fields on a contact note (REST v2 PATCH /v2/contacts/{contactId}/notes/{noteId}).
  • keap/delete-note deletes a note from a contact (REST v2 DELETE /v2/contacts/{contactId}/notes/{noteId}).
  • keap/list-notes lists notes across all contacts (REST v2 GET /v2/notes).
  • keap/create-task creates a task (REST v2 POST /v2/tasks).
  • keap/get-task retrieves a task by ID (REST v2 GET /v2/tasks/{id}).
  • keap/update-task updates named fields on a task, including marking it complete (REST v2 PATCH /v2/tasks/{id}).
  • keap/delete-task deletes a task (REST v2 DELETE /v2/tasks/{id}).
  • keap/list-tasks lists tasks (REST v2 GET /v2/tasks).
  • keap/create-company creates a company (REST v2 POST /v2/companies).
  • keap/update-company updates named fields on a company (REST v2 PATCH /v2/companies/{id}).
  • keap/get-company retrieves a company by ID (REST v2 GET /v2/companies/{id}).
  • keap/list-companies lists or searches companies (REST v2 GET /v2/companies).
  • keap/create-opportunity creates an opportunity for a contact (REST v2 POST /v2/opportunities).
  • keap/update-opportunity updates named fields on an opportunity, including moving it to another stage (REST v2 PATCH /v2/opportunities/{id}).
  • keap/get-opportunity retrieves an opportunity by ID (REST v2 GET /v2/opportunities/{id}).
  • keap/list-opportunities lists or searches opportunities (REST v2 GET /v2/opportunities).
  • keap/list-opportunity-stages lists the pipeline stages available for opportunities (REST v2 GET /v2/opportunities/stages).
  • keap/create-order creates an order and its invoice for a contact (REST v2 POST /v2/orders).
  • keap/add-order-item adds a line item to an existing order (REST v2 POST /v2/orders/{id}/items).
  • keap/get-order retrieves an order by ID (REST v2 GET /v2/orders/{id}).
  • keap/list-orders lists or searches orders and their invoices (REST v2 GET /v2/orders).
  • keap/create-order-payment records or charges a payment against an order (REST v2 POST /v2/orders/{id}/payments).
  • keap/create-product creates a product (REST v2 POST /v2/products).
  • keap/get-product retrieves a product by ID (REST v2 GET /v2/products/{id}).
  • keap/list-products lists products (REST v2 GET /v2/products).
  • keap/upload-file uploads a Base64-encoded file to the Keap file box, optionally attaching it to a contact (REST v1 POST /v1/files; v2 requires a binary multipart upload the declarative engine cannot express).
  • keap/list-files lists files in the Keap file box (REST v2 GET /v2/files).
  • keap/delete-file deletes a file from the Keap file box (REST v2 DELETE /v2/files/{id}).
  • keap/list-campaigns lists marketing campaigns (REST v2 GET /v2/campaigns).
  • keap/list-campaign-sequences lists the sequences inside a campaign, so you can pick one to add contacts to (REST v2 GET /v2/campaigns/{id}/sequences).
  • keap/add-to-sequence starts contacts into a campaign sequence, kicking off its automation (REST v2 POST /v2/campaigns/{id}/sequences/{id}:addContacts).
  • keap/remove-from-sequence removes contacts from a campaign sequence, stopping its automation for them (REST v2 POST /v2/campaigns/{id}/sequences/{id}:removeContacts).
  • keap/achieve-goal fires an API goal for a contact, triggering any automation waiting on it (REST v2 POST /v2/automations/goals/achieve).
  • keap/create-subscription starts a recurring subscription for a contact against a subscription plan (REST v2 POST /v2/subscriptions).
  • keap/get-subscription retrieves a subscription by ID (REST v2 GET /v2/subscriptions/{id}).
  • keap/list-subscriptions lists recurring subscriptions (REST v2 GET /v2/subscriptions).
  • keap/cancel-subscription deactivates a recurring subscription so it stops billing (REST v2 POST /v2/subscriptions/{id}:deactivate).
  • keap/list-transactions lists payment transactions (REST v2 GET /v2/sales/transactions).
  • keap/list-payments lists payments recorded against orders (REST v2 GET /v2/sales/payments).
  • keap/list-affiliates lists affiliates (REST v2 GET /v2/affiliates).
  • keap/list-commissions lists commissions earned by one affiliate (REST v2 GET /v2/affiliates/{id}:commissions).
  • keap/list-users lists Keap users, for assigning owners, tasks and notes (REST v2 GET /v2/users).

Known limitations

  • Every list action filters through one filter expression. Keap v2 takes a single filter string per request (for example email==name@example.com) rather than one query parameter per field. Each action's Filter field documents the fields that endpoint accepts.
  • Updates only write the fields you name. Keap v2 applies a PATCH solely to the fields listed in Fields to Update. Leave a field out of that list and its new value is ignored, even when you fill it in.
  • Uploads are Base64, and capped by Keap's own file limits. Upload File sends the file as a Base64 string on REST v1, because v2 accepts only a binary multipart upload.
  • Tag application is batched by Keap. Applying a tag can take several minutes to surface on the Tag Applied to Contact trigger.
  • Hook deliveries carry identifiers, not records. A trigger payload contains event_key, object_type and object_keys[]. Follow it with the matching Get action to fetch the full record.
  • User pickers label by first name. Keap's user listing exposes no single display-name field.
  • Keap is a single paid plan with no free option; a developer sandbox is available through the Keap developer programme.
Was this helpful?