openapi: 3.1.0 info: title: Keap Product API description: Keap Public API Documentation termsOfService: https://www.thryv.com/terms-of-use contact: name: Keap url: https://developer.keap.com/get-support email: api.keap@thryv.com license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 version: v1 servers: - url: https://api.infusionsoft.com/crm tags: - name: Product paths: /rest/v1/products/{productId}/subscriptions: post: tags: - Product summary: Create a Product Subscription description: Creates a new product subscription operationId: createProductSubscription parameters: - name: productId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateProductSubscription' required: true responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '201': description: Created content: application/json: schema: $ref: '#/components/schemas/ProductSubscription' /rest/v1/products/{productId}/image: post: tags: - Product summary: Upload a product image description: Max payload 3 megabytes, the `file_data` is base64 encoded. operationId: createProductImage parameters: - name: httpHeaders in: header required: true schema: $ref: '#/components/schemas/HttpHeaders' - name: productId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateProductImage' required: true responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '201': description: Created delete: tags: - Product summary: Delete a product image operationId: deleteProductImage parameters: - name: productId in: path required: true schema: type: integer format: int64 responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '204': description: No Content /rest/v1/products: get: tags: - Product summary: List Products description: Retrieves a list of all products operationId: listProducts parameters: - name: productSearchCommand in: query required: true schema: $ref: '#/components/schemas/ProductSearchCommand' responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '200': description: OK content: application/json: schema: $ref: '#/components/schemas/ProductList' deprecated: true post: tags: - Product summary: Create a Product description: Creates a new product operationId: createProduct requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateProduct' required: true responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '201': description: Created content: application/json: schema: $ref: '#/components/schemas/RestProductV1' /rest/v1/products/{productId}: get: tags: - Product summary: Retrieve a Product operationId: retrieveProduct parameters: - name: productId in: path required: true schema: type: integer format: int64 responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '200': description: OK content: application/json: schema: $ref: '#/components/schemas/RestProductV1' delete: tags: - Product summary: Delete a Product description: Deletes a product and its subscriptions operationId: deleteProduct parameters: - name: productId in: path required: true schema: type: integer format: int64 responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '204': description: No Content patch: tags: - Product summary: Update a Product description: Updates a Product with only the values provided in the request. operationId: updateProduct parameters: - name: productId in: path required: true schema: type: integer format: int64 requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateProduct' required: true responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '200': description: OK content: application/json: schema: $ref: '#/components/schemas/RestProductV1' /rest/v1/products/{productId}/subscriptions/{subscriptionId}: get: tags: - Product summary: Retrieve a Product Subscription operationId: retrieveProductSubscription parameters: - name: productId in: path required: true schema: type: integer format: int64 - name: subscriptionId in: path required: true schema: type: integer format: int64 responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '200': description: OK content: application/json: schema: $ref: '#/components/schemas/ProductSubscription' delete: tags: - Product summary: Delete a Product Subscription description: Deletes a product subscription operationId: deleteProductSubscription parameters: - name: productId in: path required: true schema: type: integer format: int64 - name: subscriptionId in: path required: true schema: type: integer format: int64 responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '204': description: No Content /rest/v1/products/sync: get: tags: - Product summary: Retrieve Synced Products description: The Sync endpoint returns a set of products that have been updated or created since the last result set was retrieved, minus any products that have been deleted. operationId: listProductsFromSyncToken parameters: - name: sync_token in: query required: false schema: type: string - name: syncCommand in: query required: true schema: $ref: '#/components/schemas/SyncCommand' responses: '400': description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '403': description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '409': description: Conflict content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '501': description: Not Implemented content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '405': description: Method Not Allowed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '406': description: Not Acceptable content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '412': description: Precondition Failed content: application/json: schema: $ref: '#/components/schemas/ModelAndView' '200': description: OK content: application/json: schema: $ref: '#/components/schemas/ProductStatusList' deprecated: true components: schemas: ContentDisposition: type: object properties: type: type: string name: type: string filename: type: string charset: type: string inline: type: boolean formData: type: boolean attachment: type: boolean CreateProduct: type: object properties: sku: type: string active: type: boolean product_name: type: string product_desc: type: string product_price: type: number format: double product_short_desc: type: string subscription_only: type: boolean required: - product_name CreateProductImage: type: object properties: file_name: type: string description: 'The name of the file with extension, must match file data. Acceptable file types: [.png, .gif, .jpg, .jpeg].' file_data: type: string description: The image data, base64 encoded. checksum: type: string description: SHA256 checksum of image in Hex. required: - file_data - file_name CreateProductSubscription: type: object properties: frequency: type: integer format: int32 active: type: boolean cycle_type: type: string enum: - YEAR - MONTH - WEEK - DAY plan_price: type: number format: double number_of_cycles: type: integer format: int32 subscription_plan_index: type: integer format: int32 required: - cycle_type - plan_price DefaultHttpStatusCode: allOf: - $ref: '#/components/schemas/HttpStatusCode' HttpHeaders: type: object properties: accept: type: array items: $ref: '#/components/schemas/MediaType' bearerAuth: type: string writeOnly: true basicAuth: type: string writeOnly: true allow: type: array items: $ref: '#/components/schemas/HttpMethod' uniqueItems: true cacheControl: type: string acceptLanguage: type: array items: type: object properties: range: type: string weight: type: number format: double acceptLanguageAsLocales: type: array items: type: string acceptPatch: type: array items: $ref: '#/components/schemas/MediaType' accessControlAllowCredentials: type: boolean accessControlAllowHeaders: type: array items: type: string accessControlAllowMethods: type: array items: $ref: '#/components/schemas/HttpMethod' accessControlAllowOrigin: type: string accessControlExposeHeaders: type: array items: type: string accessControlMaxAge: type: integer format: int64 accessControlRequestHeaders: type: array items: type: string accessControlRequestMethod: $ref: '#/components/schemas/HttpMethod' acceptCharset: type: array items: type: string contentDisposition: $ref: '#/components/schemas/ContentDisposition' contentLanguage: type: string etag: type: string expires: type: integer format: int64 ifMatch: type: array items: type: string ifNoneMatch: type: array items: type: string ifUnmodifiedSince: type: integer format: int64 pragma: type: string upgrade: type: string vary: type: array items: type: string host: type: object properties: hostString: type: string address: type: object properties: hostAddress: type: string address: type: string format: byte hostName: type: string linkLocalAddress: type: boolean multicastAddress: type: boolean anyLocalAddress: type: boolean loopbackAddress: type: boolean siteLocalAddress: type: boolean mcglobal: type: boolean mcnodeLocal: type: boolean mclinkLocal: type: boolean mcsiteLocal: type: boolean mcorgLocal: type: boolean canonicalHostName: type: string port: type: integer format: int32 unresolved: type: boolean hostName: type: string empty: type: boolean location: type: string format: uri all: type: object additionalProperties: type: string writeOnly: true lastModified: type: integer format: int64 date: type: integer format: int64 contentLength: type: integer format: int64 contentType: $ref: '#/components/schemas/MediaType' ifModifiedSince: type: integer format: int64 range: type: array items: $ref: '#/components/schemas/HttpRange' connection: type: array items: type: string origin: type: string HttpMethod: {} HttpRange: {} HttpStatus: allOf: - $ref: '#/components/schemas/HttpStatusCode' enum: - 100 CONTINUE - 101 SWITCHING_PROTOCOLS - 102 PROCESSING - 103 EARLY_HINTS - 200 OK - 201 CREATED - 202 ACCEPTED - 203 NON_AUTHORITATIVE_INFORMATION - 204 NO_CONTENT - 205 RESET_CONTENT - 206 PARTIAL_CONTENT - 207 MULTI_STATUS - 208 ALREADY_REPORTED - 226 IM_USED - 300 MULTIPLE_CHOICES - 301 MOVED_PERMANENTLY - 302 FOUND - 303 SEE_OTHER - 304 NOT_MODIFIED - 307 TEMPORARY_REDIRECT - 308 PERMANENT_REDIRECT - 400 BAD_REQUEST - 401 UNAUTHORIZED - 402 PAYMENT_REQUIRED - 403 FORBIDDEN - 404 NOT_FOUND - 405 METHOD_NOT_ALLOWED - 406 NOT_ACCEPTABLE - 407 PROXY_AUTHENTICATION_REQUIRED - 408 REQUEST_TIMEOUT - 409 CONFLICT - 410 GONE - 411 LENGTH_REQUIRED - 412 PRECONDITION_FAILED - 413 CONTENT_TOO_LARGE - 413 PAYLOAD_TOO_LARGE - 414 URI_TOO_LONG - 415 UNSUPPORTED_MEDIA_TYPE - 416 REQUESTED_RANGE_NOT_SATISFIABLE - 417 EXPECTATION_FAILED - 418 I_AM_A_TEAPOT - 421 MISDIRECTED_REQUEST - 422 UNPROCESSABLE_CONTENT - 422 UNPROCESSABLE_ENTITY - 423 LOCKED - 424 FAILED_DEPENDENCY - 425 TOO_EARLY - 426 UPGRADE_REQUIRED - 428 PRECONDITION_REQUIRED - 429 TOO_MANY_REQUESTS - 431 REQUEST_HEADER_FIELDS_TOO_LARGE - 451 UNAVAILABLE_FOR_LEGAL_REASONS - 500 INTERNAL_SERVER_ERROR - 501 NOT_IMPLEMENTED - 502 BAD_GATEWAY - 503 SERVICE_UNAVAILABLE - 504 GATEWAY_TIMEOUT - 505 HTTP_VERSION_NOT_SUPPORTED - 506 VARIANT_ALSO_NEGOTIATES - 507 INSUFFICIENT_STORAGE - 508 LOOP_DETECTED - 509 BANDWIDTH_LIMIT_EXCEEDED - 510 NOT_EXTENDED - 511 NETWORK_AUTHENTICATION_REQUIRED HttpStatusCode: type: object properties: error: type: boolean is1xxInformational: type: boolean is2xxSuccessful: type: boolean is3xxRedirection: type: boolean is4xxClientError: type: boolean is5xxServerError: type: boolean MediaType: type: object properties: type: type: string subtype: type: string parameters: type: object additionalProperties: type: string qualityValue: type: number format: double wildcardType: type: boolean wildcardSubtype: type: boolean subtypeSuffix: type: string charset: type: string concrete: type: boolean ModelAndView: type: object properties: view: $ref: '#/components/schemas/View' model: type: object additionalProperties: {} status: oneOf: - $ref: '#/components/schemas/DefaultHttpStatusCode' - $ref: '#/components/schemas/HttpStatus' modelMap: type: object additionalProperties: {} properties: empty: type: boolean reference: type: boolean empty: type: boolean viewName: type: string ProductList: type: object properties: products: type: array items: $ref: '#/components/schemas/Product_' count: type: integer format: int32 next: type: string previous: type: string sync_token: type: string ProductOption: type: object properties: id: type: integer format: int64 name: type: string label: type: string required: type: boolean type: type: string enum: - FixedList - Variable values: type: array items: $ref: '#/components/schemas/ProductOptionValue' min_chars: type: integer format: int32 max_chars: type: integer format: int32 allow_spaces: type: boolean can_end_with_character: type: boolean can_end_with_number: type: boolean can_contain_character: type: boolean can_contain_number: type: boolean can_start_with_character: type: boolean can_start_with_number: type: boolean text_message: type: string display_index: type: integer format: int32 ProductOptionValue: type: object properties: id: type: integer format: int64 label: type: string sku: type: string index: type: integer format: int64 is_default: type: boolean price_adjustment: type: number format: double ProductSearchCommand: type: object properties: limit: type: integer format: int32 offset: type: integer format: int32 active: type: boolean ProductStatus: type: object properties: status: type: string enum: - CREATED - UPDATED - DELETED product: $ref: '#/components/schemas/Product_' ProductStatusList: type: object properties: product_statuses: type: array items: $ref: '#/components/schemas/ProductStatus' count: type: integer format: int32 next: type: string previous: type: string sync_token: type: string ProductSubscription: type: object properties: id: type: integer format: int64 frequency: type: integer format: int32 active: type: boolean url: type: string cycle_type: type: string enum: - YEAR - MONTH - WEEK - DAY plan_price: type: number format: double subscription_plan_name: type: string number_of_cycles: type: integer format: int32 subscription_plan_index: type: integer format: int32 required: - cycle_type - id - plan_price Product_: type: object properties: id: type: integer format: int64 sku: type: string url: type: string status: type: integer format: int32 product_name: type: string product_desc: type: string product_price: type: number format: double product_short_desc: type: string subscription_only: type: boolean product_options: type: array items: $ref: '#/components/schemas/ProductOption' subscription_plans: type: array items: $ref: '#/components/schemas/SubscriptionPlan_' RestProductV1: type: object properties: id: type: integer format: int64 sku: type: string active: type: boolean url: type: string product_name: type: string product_desc: type: string product_price: type: number format: double product_short_desc: type: string subscription_only: type: boolean subscription_plans: type: array items: $ref: '#/components/schemas/ProductSubscription' required: - id - product_name SubscriptionPlan_: type: object properties: id: type: integer format: int64 cycle: type: integer format: int32 frequency: type: integer format: int32 url: type: string active: type: boolean subscription_plan_name: type: string number_of_cycles: type: integer format: int32 plan_price: type: number format: double subscription_plan_index: type: integer format: int32 SyncCommand: type: object properties: limit: type: integer format: int32 offset: type: integer format: int32 View: type: object properties: contentType: type: string securitySchemes: oauth2: type: oauth2 flows: authorizationCode: authorizationUrl: https://accounts.infusionsoft.com/app/oauth/authorize tokenUrl: https://api.infusionsoft.com/token scopes: {} security: - oauth2: []