{"openapi":"3.0.0","info":{"title":"Pitchlane API","version":"0.1.0","description":"Pitchlane.com's Public API for creating and managing Pitchlane campaigns and videos. We will be adding more endpoints over time. If you have any questions or need help, please contact us at [support@pitchlane.com](mailto:support@pitchlane.com)."},"servers":[{"url":"https://api.pitchlane.com/api/public/v1"}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"}},"schemas":{"trigger":{"type":"string","enum":["VIDEO_RENDERED","VIDEO_CREATED","VIDEO_VIEWED","VIDEO_FIRST_VIEWED","VIDEO_STARTED","VIDEO_FIRST_STARTED","VIDEO_FINISHED","VIDEO_FIRST_FINISHED","VIDEO_RENDERED_FULLY","VIDEO_UNRENDERABLE"],"description":"The video event that will trigger the webhook. VIDEO_RENDERED_FULLY is for when all optimisations for the video have been made, however you probably don't need this webhook; you should use VIDEO_RENDERED instead. VIDEO_UNRENDERABLE is triggered when a video cannot be rendered - either due to the website or lead being invalid or our bot unable to access it. Not all errors trigger this webhook - Unexpected/Internal Errors do not, so they can be fixed and retried by our team."},"VariableConfig":{"type":"object","properties":{"label":{"type":"string","description":"The display label for the variable"},"required":{"type":"boolean","description":"Indicates whether the variable is required"},"validator":{"type":"object","oneOf":[{"$ref":"#/components/schemas/URLValidator"},{"$ref":"#/components/schemas/EmailValidator"}]}}},"URLValidator":{"type":"object","properties":{"type":{"type":"string","enum":["url"],"description":"Specifies that the validator is of URL type"},"domain":{"type":"string","nullable":true,"description":"The specific domain to validate against, if applicable"}}},"EmailValidator":{"type":"object","properties":{"type":{"type":"string","enum":["email"],"description":"Specifies that the validator is of email type"}}},"CampaignSummary":{"type":"object","properties":{"id":{"type":"string","example":"o6duFik0_UNSUGPCn1LTm","description":"The unique identifier for the campaign."},"name":{"type":"string","description":"The name of the campaign."},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the campaign."},"variableSchema":{"type":"object","nullable":true,"description":"The schema for the variables associated with the campaign","additionalProperties":{"$ref":"#/components/schemas/VariableConfig"}},"examplePayload":{"type":"object","nullable":true,"description":"An example payload that adheres to the variable schema","additionalProperties":true}}},"VideoData":{"type":"object","additionalProperties":true,"description":"A dynamic object containing specific data elements. In addition to the fields specified below, you must use the campaign's schema to specify the required variables. The full schema can be fetched from [/campaign/{campaignId}/schema](/docs/#/campaigns/get_campaigns__campaignId__schema).","properties":{"originalData":{"type":"string","additionalProperties":true,"nullable":true,"description":"Specify either `originalData` or `originalRow` to store the original data that was used to create the video."},"originalRow":{"type":"string","additionalProperties":true,"nullable":true,"description":"Specify either `originalData` or `originalRow` to store the original data that was used to create the video."},"originalRowIndex":{"type":"integer","nullable":true,"description":"If the video was imported from a CSV, this is the row number where the video data was found."},"originalUid":{"type":"string","nullable":true,"description":"A unique identifier for the video, used to detect duplicates. If not specified, the video will be considered unique."},"first_name":{"type":"string","description":"The first name of the individual"},"company_name":{"type":"string","description":"The name of the company"},"email":{"type":"string","format":"email","description":"The email address"}}},"VariableIssue":{"type":"object","properties":{"affectedRows":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"value":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}}}}}}},"security":[{"apiKey":[]}],"tags":[{"name":"Campaigns","description":"Endpoints for creating and managing campaigns"},{"name":"Videos","description":"Endpoints for creating and managing videos"},{"name":"Webhooks","description":"Endpoints for creating and managing webhooks"}],"paths":{"/campaigns/{campaignId}/videos":{"post":{"summary":"Create (or Update) a video in a Campaign","tags":["Videos"],"parameters":[{"in":"path","name":"campaignId","required":true,"schema":{"type":"string"},"description":"The unique identifier of the campaign"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"queueForRender":{"type":"boolean","default":true,"description":"If true, the video will automatically be added to the rendering queue to be rendered (default). If false, the video will be created in Pitchlane but will not be rendered until the \"Render all Videos\" button is pressed in the Pitchlane UI."},"title":{"type":"string","nullable":true,"description":"The title of the video to create. If not specified, the title will be generated following the campaign's `titleTemplate`."},"variables":{"type":"object","description":"A dynamic object containing specific data elements. The full schema can be fetched from [/campaign/{campaignId}/schema](/docs/#/campaigns/get_campaigns__campaignId__schema).","properties":{"originalData":{"type":"string","nullable":true,"description":"Specify either `originalData` or `originalRow` to store the original data that was used to create the video."},"originalRow":{"type":"string","nullable":true,"description":"Specify either `originalData` or `originalRow` to store the original data that was used to create the video."},"originalRowIndex":{"type":"integer","nullable":true,"description":"If the video was imported from a CSV, this is the row number where the video data was found."},"originalUid":{"type":"string","nullable":true,"description":"A unique identifier for the video, used to detect duplicates. If not specified, the video will be considered unique."}},"additionalProperties":true}},"required":["variables"]}}}},"responses":{"200":{"description":"Video created successfully","content":{"application/json":{"schema":{"type":"object","description":"Detailed information about the created video.","properties":{"id":{"type":"string","example":"DHFG2C09n_3qrsSymZjjm","description":"The full ID of the video created."},"shortId":{"type":"string","example":"3qrsSymZjjm","description":"The short ID of the video created (used in the final video URL)."}}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"string","example":"Invalid URL: https://example.com"},"description":"A list of error messages detailing what was incorrect about the input."}}}}}}}}},"/campaigns/{campaignId}/webhooks":{"post":{"summary":"Create a campaign-specific webhook subscription.","description":"Notify the specified URL when a video event occurs. For general (not specific to one campaign) webhooks, use the /webhooks endpoint.","tags":["Webhooks"],"parameters":[{"in":"path","name":"campaignId","required":false,"schema":{"type":"string"},"description":"The unique identifier of the campaign."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"webhookUrl":{"type":"string","description":"The URL to send the webhook to when the event occurs."},"campaignId":{"type":"string","required":false,"description":"The unique identifier of the campaign."},"trigger":{"$ref":"#/components/schemas/trigger"}}}}}},"responses":{"200":{"description":"The webhook was successfully created.","content":{"application/json":{"schema":{"type":"object","description":"Information about the webhook created.","properties":{"trigger":{"$ref":"#/components/schemas/trigger"},"webhookUrl":{"type":"string","description":"The URL the webhook will be sent to when the trigger occurs."},"id":{"type":"string","example":"DHFG2C09n_3qrsSymZjjm","description":"The ID of the webhook created."}}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"received":{"type":"string","example":"VIDEO_DEFENESTRATED","description":"The bad input that was received."},"code":{"type":"string","example":"invalid_enum_value","description":"The error code for the bad input."},"message":{"type":"string","example":"Invalid url","description":"A message detailing what was incorrect about the input."},"path":{"type":"string","example":"trigger","description":"The schema path to the bad input."},"options":{"$ref":"#/components/schemas/trigger","description":"The valid options for the input.","nullable":true}}},"description":"A list of error messages detailing what was incorrect about the input."}}}}}},"404":{"description":"Campaign not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Campaign not found"}}}}}}}},"delete":{"summary":"Delete a campaign-specific webhook subscription.","description":"Delete a webhook subscription. If the webhook is associated with a campaign, the campaignId must be provided. If the webhook is not associated with a campaign, the campaignId must be omitted, and the endpoint /webhooks must be used instead.","tags":["Webhooks"],"parameters":[{"in":"path","name":"campaignId","required":false,"schema":{"type":"string"},"description":"The unique identifier of the campaign."},{"in":"query","name":"webhookUrl","required":true,"schema":{"type":"string"},"description":"The URL of the webhook to be deleted."},{"in":"query","name":"trigger","required":true,"schema":{"$ref":"#/components/schemas/trigger"}}],"responses":{"204":{"description":"The webhook was successfully deleted."},"400":{"description":"Invalid query data","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"validation":{"type":"string","example":"url","description":"The type of validation that failed."},"code":{"type":"string","example":"invalid_string","description":"The error code for the bad input."},"message":{"type":"string","example":"Invalid url","description":"A message detailing what was incorrect about the input."},"path":{"type":"string","example":"webhookUrl","description":"The schema path to the bad input."}}},"description":"A list of error messages detailing what was incorrect about the input."}}}}}},"404":{"description":"Campaign or webhook not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Campaign not found"}}}}}}}}},"/webhooks":{"post":{"summary":"Create a webhook subscription.","description":"Notify the specified URL when a video event occurs. If a campaignId is provided, the webhook will only be triggered by events in that campaign. If no campaignId is provided, the webhook will be triggered by events in any campaign.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"webhookUrl":{"type":"string","description":"The URL to send the webhook to when the event occurs."},"campaignId":{"type":"string","required":false,"description":"The unique identifier of the campaign."},"trigger":{"$ref":"#/components/schemas/trigger"}}}}}},"responses":{"200":{"description":"The webhook was successfully created.","content":{"application/json":{"schema":{"type":"object","description":"Information about the webhook created.","properties":{"trigger":{"$ref":"#/components/schemas/trigger"},"webhookUrl":{"type":"string","description":"The URL the webhook will be sent to when the trigger occurs."},"id":{"type":"string","example":"DHFG2C09n_3qrsSymZjjm","description":"The ID of the webhook created."},"userId":{"type":"string","description":"The unique identifier of the user."},"createdAt":{"type":"string","description":"The date and time the webhook was created."}}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"received":{"type":"string","example":"VIDEO_DEFENESTRATED","description":"The bad input that was received."},"code":{"type":"string","example":"invalid_enum_value","description":"The error code for the bad input."},"message":{"type":"string","example":"Invalid enum value. Expected 'VIDEO_RENDERED' | 'VIDEO_RENDERED_FULLY' | 'VIDEO_CREATED' | 'VIDEO_VIEWED' | 'VIDEO_FIRST_VIEWED' | 'VIDEO_STARTED' | 'VIDEO_FIRST_STARTED' | 'VIDEO_FINISHED' | 'VIDEO_FIRST_FINISHED', received 'VIDEO_DEFENESTRATED'.","description":"A message detailing what was incorrect about the input."},"path":{"type":"string","example":"trigger","description":"The schema path to the bad input."},"options":{"$ref":"#/components/schemas/trigger","description":"The valid options for the input.","nullable":true}}},"description":"A list of error messages detailing what was incorrect about the input."}}}}}},"404":{"description":"Campaign not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"campaign_not_found"}}}}}}}},"delete":{"summary":"Delete a webhook subscription.","description":"Delete a webhook subscription. If the webhook is associated with a campaign, the campaignId must be provided. If the webhook is not associated with a campaign, the campaignId must be omitted.","tags":["Webhooks"],"parameters":[{"in":"query","name":"webhookUrl","required":true,"schema":{"type":"string"},"description":"The URL of the webhook to be deleted."},{"in":"query","name":"trigger","required":true,"schema":{"$ref":"#/components/schemas/trigger"}}],"responses":{"204":{"description":"The webhook was successfully deleted."},"400":{"description":"Invalid query data","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"validation":{"type":"string","example":"url","description":"The type of validation that failed."},"code":{"type":"string","example":"invalid_string","description":"The error code for the bad input."},"message":{"type":"string","example":"Invalid url","description":"A message detailing what was incorrect about the input."},"path":{"type":"string","example":"webhookUrl","description":"The schema path to the bad input."}}},"description":"A list of error messages detailing what was incorrect about the input."}}}}}},"404":{"description":"Campaign or webhook not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Webhook not found"}}}}}}}},"get":{"summary":"Get the webhook subscriptions for a user and campaign.","description":"Get a list of webhook subscriptions. If a campaignId is provided, webhooks from other campaigns will be omitted.","tags":["Webhooks"],"responses":{"200":{"description":"A list of webhook objects.","content":{"application/json":{"schema":{"type":"array","items":[{"type":"object","description":"Information about the webhook created.","properties":{"trigger":{"$ref":"#/components/schemas/trigger"},"webhookUrl":{"type":"string","description":"The URL the webhook will be sent to when the trigger occurs."},"id":{"type":"string","description":"The unique identifier of the webhook."},"userId":{"type":"string","description":"The unique identifier of the user."},"createdAt":{"type":"string","description":"The date and time the webhook was created."},"campaignId":{"type":"string","description":"The unique identifier of the campaign.","nullable":true},"campaign":{"type":"object","description":"The campaign the webhook is associated with.","nullable":true,"properties":{"_id":{"type":"string","description":"The unique identifier of the campaign."},"name":{"type":"string","description":"The name of the campaign."}}}}}]}}}}}},"put":{"summary":"Update a webhook subscription.","description":"Update a webhook subscription. If the webhook is associated with a campaign, the campaignId must be provided. If the webhook is not associated with a campaign, the campaignId must be omitted.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the webhook."},"webhookUrl":{"type":"string","description":"The URL to send the webhook to when the event occurs."},"campaignId":{"type":"string","required":false,"description":"The unique identifier of the campaign."},"trigger":{"$ref":"#/components/schemas/trigger"}}}}}},"responses":{"200":{"description":"The webhook was successfully updated.","content":{"application/json":{"schema":{"type":"object","description":"The webhook object.","properties":{"trigger":{"$ref":"#/components/schemas/trigger"},"webhookUrl":{"type":"string","description":"The URL the webhook will be sent to when the trigger occurs."},"id":{"type":"string","example":"DHFG2C09n_3qrsSymZjjm","description":"The ID of the webhook."},"createdAt":{"type":"string","example":"2024-08-21T13:05:39.923Z","description":"The date and time the webhook was created."},"userId":{"type":"string","example":"google-oauth2|123456789","description":"The ID of the user who created the webhook."}}}}}},"400":{"description":"Invalid input data","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"received":{"type":"string","example":"VIDEO_DEFENESTRATED","description":"The bad input that was received."},"code":{"type":"string","example":"invalid_enum_value","description":"The error code for the bad input."},"message":{"type":"string","example":"Invalid url","description":"A message detailing what was incorrect about the input."},"path":{"type":"string","example":"trigger","description":"The schema path to the bad input."},"options":{"$ref":"#/components/schemas/trigger","description":"The valid options for the input.","nullable":true}}},"description":"A list of error messages detailing what was incorrect about the input."}}}}}},"404":{"description":"Campaign or webhook not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Campaign not found"}}}}}}}}},"/campaigns/{campaignId}/schemas":{"get":{"tags":["Campaigns"],"summary":"Retrieve the variable schema and lead schema mapping for a specific campaign","parameters":[{"in":"path","name":"campaignId","required":true,"schema":{"type":"string"},"description":"The unique identifier of the campaign for which the schema is being retrieved"}],"responses":{"200":{"description":"Returns both variable and lead schema mappings along with their example payloads","content":{"application/json":{"schema":{"type":"object","properties":{"variableSchema":{"type":"object","description":"The schema for the variables associated with the campaign","additionalProperties":{"$ref":"#/components/schemas/VariableConfig"}},"exampleVariableSchemaPayload":{"type":"object","description":"An example payload that adheres to the variable schema","additionalProperties":true},"leadSchemaMapping":{"type":"object","description":"The schema for the leads associated with the campaign. The keys of this should be what goes in your API request body.","additionalProperties":true},"exampleLeadSchemaMappingPayload":{"type":"object","description":"An example payload that adheres to the lead schema","additionalProperties":true}}}}}},"404":{"description":"Campaign not found"}}}},"/campaigns/{campaignId}/schema":{"get":{"tags":["Campaigns"],"summary":"Retrieve the variable schema for a specific campaign","parameters":[{"in":"path","name":"campaignId","required":true,"schema":{"type":"string"},"description":"The unique identifier of the campaign for which the schema is being retrieved"}],"responses":{"200":{"description":"Returns the variable schema associated with the campaign","content":{"application/json":{"schema":{"type":"object","properties":{"variableSchema":{"type":"object","description":"The schema for the variables associated with the campaign","additionalProperties":{"$ref":"#/components/schemas/VariableConfig"}},"examplePayload":{"type":"object","description":"An example payload that adheres to the variable schema","additionalProperties":true}}}}}},"404":{"description":"Campaign not found"}}}},"/campaigns":{"get":{"tags":["Campaigns"],"summary":"List of all your campaigns","responses":{"200":{"description":"Returns a list of campaign summaries.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CampaignSummary"}}}}}}}},"/campaigns/{campaignId}/lead-schema-mapping":{"get":{"tags":["Campaigns"],"summary":"Retrieve the lead schema mapping for a specific campaign","parameters":[{"in":"path","name":"campaignId","required":true,"schema":{"type":"string"},"description":"The unique identifier of the campaign for which the schema is being retrieved"}],"responses":{"200":{"description":"Returns the lead schema mapping associated with the campaign","content":{"application/json":{"schema":{"type":"object","properties":{"leadSchemaMapping":{"type":"object","description":"The mapping for the campaign's lead schema. The keys of this should be what goes in your API request body."},"examplePayload":{"type":"object","description":"An example estimated API request body payload","additionalProperties":true}}}}}},"404":{"description":"Campaign not found"}}}},"/campaigns/{campaignId}/videos/import/v2":{"post":{"tags":["Videos"],"summary":"Import multiple videos into a campaign","description":"Import multiple videos into a campaign with their associated variables and metadata. The lead schema endpoint should be used first to set up the lead schema and mappings.","parameters":[{"in":"path","name":"campaignId","required":true,"schema":{"type":"string"},"description":"The unique identifier of the campaign where videos are to be imported"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"videos":{"type":"array","items":{"$ref":"#/components/schemas/VideoData"}},"titleTemplate":{"type":"string","nullable":true,"description":"The template to use for video titles (e.g. \"Video for {{first_name}}\")"},"importId":{"type":"string","nullable":true,"description":"The import ID to group the video under. This is usually the CSV the video was imported from but can be any string to identify a grouping of videos. If not specified, defaults to a random nanoid."},"renderTestVideo":{"type":"boolean","nullable":true,"description":"If true, the first video in the list will be rendered as a test video. If the campaign does not already have a test video, it will be set to this video. If not specified, the campaign's test video will not be changed and no videos will be automatically queued to render. Has no effect if `queueAllVideosForRender` is true."},"queueAllVideosForRender":{"type":"boolean","nullable":true,"description":"If true, the videos will be queued for rendering. If not specified, the videos will NOT be queued for rendering. Has no effect if `renderTestVideo` is true."},"duplicateIdentifierField":{"type":"string","nullable":true,"description":"The field name to use for duplicate detection. If not specified, will use the campaign's default duplicate identifier field."}}}}}},"responses":{"200":{"description":"Videos successfully imported","content":{"application/json":{"schema":{"type":"object","properties":{"inserted":{"type":"integer","description":"Number of videos successfully imported"},"upserted":{"type":"integer","description":"Number of videos successfully updated (if upsert=true)"},"duplicates":{"type":"integer","description":"Number of duplicate entries detected"},"invalidRows":{"type":"integer","description":"Number of rows that failed validation"},"variableIssues":{"type":"object","nullable":true,"additionalProperties":{"$ref":"#/components/schemas/VariableIssue"},"description":"Details of issues related to specific variables"},"testVideoQueued":{"type":"boolean","description":"Whether a test video was queued for rendering"}}}}}},"400":{"description":"Error in request format or validation","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","nullable":true,"description":"General error message describing the nature of the error"},"variableIssues":{"type":"object","nullable":true,"additionalProperties":{"$ref":"#/components/schemas/VariableIssue"},"description":"Details of issues related to specific variables"},"duplicates":{"type":"integer","nullable":true,"description":"Number of duplicate entries detected"}}}}}},"404":{"description":"Campaign not found"}}}},"/campaigns/{campaignId}/videos/import":{"post":{"tags":["Videos"],"summary":"Import multiple videos into a campaign","parameters":[{"in":"path","name":"campaignId","required":true,"schema":{"type":"string"},"description":"The unique identifier of the campaign where videos are to be imported"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"videos":{"type":"array","items":{"$ref":"#/components/schemas/VideoData"}},"titleTemplate":{"type":"string","nullable":true,"description":"The template to use for video titles (e.g. \"Video for {{first_name}}\")"},"importId":{"type":"string","nullable":true,"description":"The import ID to group the video under. This is usually the CSV the video was imported from but can be any string to identify a grouping of videos. If not specified, defaults to a random nanoid."},"renderTestVideo":{"type":"boolean","nullable":true,"description":"If true, the first video in the list will be rendered as a test video. If the campaign does not already have a test video, it will be set to this video. If not specified, the campaign's test video will not be changed and no videos will be automatically queued to render. Has no effect if `queueAllVideosForRender` is true."},"queueAllVideosForRender":{"type":"boolean","nullable":true,"description":"If true, the videos will be queued for rendering. If not specified, the videos will NOT be queued for rendering. Has no effect if `renderTestVideo` is true."}}}}}},"responses":{"200":{"description":"Videos successfully imported","content":{"application/json":{"schema":{"type":"object","properties":{"inserted":{"type":"integer","description":"Number of videos successfully imported"},"duplicates":{"type":"integer","description":"Number of duplicate entries detected"}}}}}},"400":{"description":"Error in request format or validation","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","nullable":true,"description":"General error message describing the nature of the error"},"variableIssues":{"type":"object","nullable":true,"additionalProperties":{"$ref":"#/components/schemas/VariableIssue"},"description":"Details of issues related to specific variables"},"duplicates":{"type":"integer","nullable":true,"description":"Number of duplicate entries detected"}}}}}}}}}}}