- Documentation
- Integrations
- Apps
- Keap integration
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
- Open your workspace in TaskJuice and navigate to Connections.
- Choose Keap and click Connect.
- Sign in to Keap as a user with permission to install third-party applications.
- Keap issues a single OAuth scope (
full) covering every REST endpoint the integration uses, so there is nothing to pick. - 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-addedtriggers when a new contact is created in Keap (REST Hookcontact.addevent). 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 onobject_keys[0].id. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/contact-updatedtriggers when a contact is updated in Keap (REST Hookcontact.editevent). 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 onobject_keys[0].id. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/tag-appliedtriggers when a tag is applied to a contact in Keap (REST HookcontactGroup.appliedevent). 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, fetchobject_keys[].apiUrldirectly with an HTTP step using the same connection. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/tag-createdtriggers when a new tag is created in Keap (REST HookcontactGroup.addevent). 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, fetchobject_keys[].apiUrldirectly with an HTTP step using the same connection. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/opportunity-addedtriggers when a new sales opportunity is created in Keap (REST Hookopportunity.addevent). 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, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/opportunity-stage-movedtriggers when an opportunity moves to a different pipeline stage in Keap (REST Hookopportunity.stage_moveevent). 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, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/company-addedtriggers when a new company is created in Keap (REST Hookcompany.addevent). 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, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/note-addedtriggers when a new note is created in Keap (REST Hooknote.addevent). 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 onobject_keys[0].id. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/task-addedtriggers when a new task is created in Keap (REST Hooktask.addevent). To watch tasks for a single assignee, add a downstream Filter on the fetched task's user.keap/appointment-addedtriggers when a new appointment is created in Keap (REST Hookappointment.addevent). 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, fetchobject_keys[].apiUrldirectly with an HTTP step using the same connection. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/invoice-addedtriggers when a new invoice is created in Keap (REST Hookinvoice.addevent). 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, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/payment-addedtriggers when a payment is added to an invoice in Keap (REST Hookinvoice.payment.addevent). The delivery carries changed-object references only; fetch the payment to filter by payment type.keap/order-addedtriggers when a new order is created in Keap (REST Hookorder.addevent). 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 onobject_keys[0].id. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/subscription-addedtriggers when a new subscription is created in Keap (REST Hooksubscription.addevent). 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, fetchobject_keys[].apiUrldirectly with an HTTP step using the same connection. Keap batches, soobject_keyscan carry more than one id: Loop over it (type: 'array',arrayPath: 'object_keys') when a delivery may name several.keap/product-addedtriggers when a new product is created in Keap (REST Hookproduct.addevent). 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, soobject_keyscan 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-sentpolls Keap's sent-email records (REST v2GET /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-addedpolls Keap's file box (REST v2GET /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-contactcreates a contact in Keap (REST v2POST /v2/contacts).keap/upsert-contactcreates a contact, or updates the existing one that matches on the chosen duplicate-handling fields (REST v2POST /v2/contacts?duplicate_option=).keap/update-contactupdates named fields on a contact (REST v2PATCH /v2/contacts/{id}). Only fields listed in Fields to Update are written.keap/get-contactretrieves a single contact by ID (REST v2GET /v2/contacts/{id}).keap/list-contactslists or searches contacts (REST v2GET /v2/contacts). Use Filter to find a contact by email.keap/delete-contactpermanently deletes a contact (REST v2DELETE /v2/contacts/{id}).keap/get-contact-modelretrieves the contact custom-field model, including every custom field ID and its options (REST v2GET /v2/contacts/model).keap/apply-tagapplies a tag to one or more contacts (REST v2POST /v2/tags/{tagId}/contacts:applyTags).keap/remove-tagremoves an applied tag from one or more contacts (REST v2POST /v2/tags/{tagId}/contacts:removeTags).keap/create-tagcreates a tag (REST v2POST /v2/tags).keap/create-tag-categorycreates a tag category (REST v2POST /v2/tags/categories).keap/list-tagslists tags (REST v2GET /v2/tags).keap/list-tag-categorieslists tag categories (REST v2GET /v2/tags/categories).keap/list-tagged-contactslists every contact carrying a given tag (REST v2GET /v2/tags/{tagId}/contacts).keap/send-emailsends an email to one or more contacts through Keap and records it on their timeline (REST v2POST /v2/emails:send).keap/create-email-recordrecords an email that was sent outside Keap onto a contact timeline, without sending anything (REST v2POST /v2/emails).keap/create-noteadds a note to a contact (REST v2POST /v2/contacts/{contactId}/notes).keap/get-noteretrieves a note on a contact (REST v2GET /v2/contacts/{contactId}/notes/{noteId}).keap/update-noteupdates named fields on a contact note (REST v2PATCH /v2/contacts/{contactId}/notes/{noteId}).keap/delete-notedeletes a note from a contact (REST v2DELETE /v2/contacts/{contactId}/notes/{noteId}).keap/list-noteslists notes across all contacts (REST v2GET /v2/notes).keap/create-taskcreates a task (REST v2POST /v2/tasks).keap/get-taskretrieves a task by ID (REST v2GET /v2/tasks/{id}).keap/update-taskupdates named fields on a task, including marking it complete (REST v2PATCH /v2/tasks/{id}).keap/delete-taskdeletes a task (REST v2DELETE /v2/tasks/{id}).keap/list-taskslists tasks (REST v2GET /v2/tasks).keap/create-companycreates a company (REST v2POST /v2/companies).keap/update-companyupdates named fields on a company (REST v2PATCH /v2/companies/{id}).keap/get-companyretrieves a company by ID (REST v2GET /v2/companies/{id}).keap/list-companieslists or searches companies (REST v2GET /v2/companies).keap/create-opportunitycreates an opportunity for a contact (REST v2POST /v2/opportunities).keap/update-opportunityupdates named fields on an opportunity, including moving it to another stage (REST v2PATCH /v2/opportunities/{id}).keap/get-opportunityretrieves an opportunity by ID (REST v2GET /v2/opportunities/{id}).keap/list-opportunitieslists or searches opportunities (REST v2GET /v2/opportunities).keap/list-opportunity-stageslists the pipeline stages available for opportunities (REST v2GET /v2/opportunities/stages).keap/create-ordercreates an order and its invoice for a contact (REST v2POST /v2/orders).keap/add-order-itemadds a line item to an existing order (REST v2POST /v2/orders/{id}/items).keap/get-orderretrieves an order by ID (REST v2GET /v2/orders/{id}).keap/list-orderslists or searches orders and their invoices (REST v2GET /v2/orders).keap/create-order-paymentrecords or charges a payment against an order (REST v2POST /v2/orders/{id}/payments).keap/create-productcreates a product (REST v2POST /v2/products).keap/get-productretrieves a product by ID (REST v2GET /v2/products/{id}).keap/list-productslists products (REST v2GET /v2/products).keap/upload-fileuploads a Base64-encoded file to the Keap file box, optionally attaching it to a contact (REST v1POST /v1/files; v2 requires a binary multipart upload the declarative engine cannot express).keap/list-fileslists files in the Keap file box (REST v2GET /v2/files).keap/delete-filedeletes a file from the Keap file box (REST v2DELETE /v2/files/{id}).keap/list-campaignslists marketing campaigns (REST v2GET /v2/campaigns).keap/list-campaign-sequenceslists the sequences inside a campaign, so you can pick one to add contacts to (REST v2GET /v2/campaigns/{id}/sequences).keap/add-to-sequencestarts contacts into a campaign sequence, kicking off its automation (REST v2POST /v2/campaigns/{id}/sequences/{id}:addContacts).keap/remove-from-sequenceremoves contacts from a campaign sequence, stopping its automation for them (REST v2POST /v2/campaigns/{id}/sequences/{id}:removeContacts).keap/achieve-goalfires an API goal for a contact, triggering any automation waiting on it (REST v2POST /v2/automations/goals/achieve).keap/create-subscriptionstarts a recurring subscription for a contact against a subscription plan (REST v2POST /v2/subscriptions).keap/get-subscriptionretrieves a subscription by ID (REST v2GET /v2/subscriptions/{id}).keap/list-subscriptionslists recurring subscriptions (REST v2GET /v2/subscriptions).keap/cancel-subscriptiondeactivates a recurring subscription so it stops billing (REST v2POST /v2/subscriptions/{id}:deactivate).keap/list-transactionslists payment transactions (REST v2GET /v2/sales/transactions).keap/list-paymentslists payments recorded against orders (REST v2GET /v2/sales/payments).keap/list-affiliateslists affiliates (REST v2GET /v2/affiliates).keap/list-commissionslists commissions earned by one affiliate (REST v2GET /v2/affiliates/{id}:commissions).keap/list-userslists Keap users, for assigning owners, tasks and notes (REST v2GET /v2/users).
Known limitations
- Every list action filters through one
filterexpression. Keap v2 takes a single filter string per request (for exampleemail==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
PATCHsolely 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_typeandobject_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.