> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pictory.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Generate Highlights from Custom Transcript

> Generate AI-powered video highlights from an edited or custom transcript

## Overview

Generate concise video highlights from your own custom or edited transcript. This endpoint is useful when you have manually edited the transcription output or want to provide your own transcript data directly. The AI analyzes your transcript and identifies the most important segments to create a summary of your desired duration.

**What you will accomplish:**

* Generate highlights from manually edited transcripts
* Use custom transcript data that does not come from the transcription API
* Create summaries from transcripts you have corrected or enhanced
* Apply highlights to videos with pre-existing transcript data

<Note>
  You need a valid API key to use this endpoint. Get your API key from the [API Access page](https://app.pictory.ai/api-access) in your Pictory dashboard.
</Note>

<Tip>
  If you have not edited the transcript and want highlights from a transcription job, use the [Generate Highlights from Transcription Job](/api-reference/transcription/generate-highlights-from-job) endpoint instead - it is simpler and requires less data.
</Tip>

***

## Request Headers

<ParamField header="Authorization" type="string" required>
  API key for authentication

  ```
  Authorization: YOUR_API_KEY
  ```
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be set to `application/json`

  ```
  Content-Type: application/json
  ```
</ParamField>

***

## Body Parameters

<ParamField body="transcript" type="object[]" required>
  Array of sentence-level transcript segments with word-level timing information.

  <Warning>
    The "Try it now" form cannot properly handle nested array inputs. Please use cURL, Postman, or one of the code examples below to test this endpoint.
  </Warning>

  Each sentence object must contain:

  * `uid` (string, required): Unique identifier for the sentence
  * `speakerId` (number, required): Speaker identifier (e.g., `1`)
  * `words` (array, required): Array of word objects

  Each word object must contain:

  * `uid` (string, required): Unique identifier for the word
  * `word` (string, required): The word text
  * `start_time` (number, required): Start time in seconds (supports decimals)
  * `end_time` (number, required): End time in seconds (supports decimals)
  * `speakerId` (number, required): Speaker identifier
  * `sentence_index` (number, required): Index of the sentence

  Example format:

  ```json theme={null}
  [
    {
      "uid": "sentence-1",
      "speakerId": 1,
      "words": [
        {
          "uid": "word-1",
          "word": "Important",
          "start_time": 0.0,
          "end_time": 0.5,
          "speakerId": 1,
          "sentence_index": 0
        },
        {
          "uid": "word-2",
          "word": "content",
          "start_time": 0.5,
          "end_time": 1.0,
          "speakerId": 1,
          "sentence_index": 0
        }
      ]
    }
  ]
  ```
</ParamField>

<ParamField body="highlight_duration" type="integer" required>
  Target duration for the video summary in seconds. The AI will select highlights that fit within this duration.

  Example: `30` for a 30-second summary, `60` for a 1-minute summary
</ParamField>

<ParamField body="duration" type="integer" optional default="0">
  Total duration of the source video in seconds. This helps the AI understand the full context when generating highlights.

  Example: `120` for a 2-minute video, `300` for a 5-minute video
</ParamField>

<ParamField body="webhook" type="string" optional>
  Webhook URL where the summary results will be posted when processing completes.

  Example: `https://your-domain.com/api/webhooks/video-summary`
</ParamField>

<ParamField body="language" type="string" optional default="en">
  Language code for the transcript content.

  Supported values: `en` (English), `es` (Spanish), `fr` (French), `de` (German), `it` (Italian), `pt` (Portuguese), and more.

  Example: `en` for English, `es` for Spanish
</ParamField>

***

## Response

<ResponseField name="success" type="boolean">
  Indicates whether the request was successfully queued for processing
</ResponseField>

<ResponseField name="data" type="object">
  Contains the job information

  <Expandable title="data properties">
    <ResponseField name="jobId" type="string">
      Unique identifier for the highlights generation job. Use this ID to track the job status via the [Get Job by ID API](/api-reference/jobs/get-transcription-job-by-id).
    </ResponseField>
  </Expandable>
</ResponseField>

***

## Response Examples

<ResponseExample>
  ```json 200 - Success theme={null}
  {
    "success": true,
    "data": {
      "jobId": "bbd75639-c3cb-4add-bf7b-e4e39cffb3b0"
    }
  }
  ```

  ```json 400 - Bad Request (Validation Error) theme={null}
  {
    "code": "INVALID_REQUEST_BODY",
    "message": "Request body validation failed.",
    "fields": [
      {
        "name": "transcript",
        "errors": "transcript is required"
      }
    ]
  }
  ```

  ```json 401 - Unauthorized theme={null}
  {
    "message": "Unauthorized"
  }
  ```
</ResponseExample>

### Job Status Response (via Get Job API)

While the highlights job is processing:

```json theme={null}
{
  "job_id": "bbd75639-c3cb-4add-bf7b-e4e39cffb3b0",
  "success": true,
  "data": {
    "status": "in-progress"
  }
}
```

When the highlights job completes, you will receive the full result with highlight markers via webhook or by polling the [Get Job by ID API](/api-reference/jobs/get-transcription-job-by-id).

***

## Code Examples

<Tip>
  Replace `YOUR_API_KEY` with your actual API key that starts with `pictai_`
</Tip>

<CodeGroup>
  ```bash cURL theme={null}
  curl --location 'https://api.pictory.ai/pictoryapis/v2/transcription/highlights' \
  --header 'Authorization: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
      "transcript": [
          {
              "uid": "sentence-1",
              "speakerId": 1,
              "words": [
                  {
                      "uid": "word-1-1",
                      "word": "Click",
                      "start_time": 0.64,
                      "end_time": 0.96,
                      "speakerId": 1,
                      "sentence_index": 0
                  },
                  {
                      "uid": "word-1-2",
                      "word": "the",
                      "start_time": 0.96,
                      "end_time": 1.12,
                      "speakerId": 1,
                      "sentence_index": 0
                  },
                  {
                      "uid": "word-1-3",
                      "word": "play",
                      "start_time": 1.12,
                      "end_time": 1.36,
                      "speakerId": 1,
                      "sentence_index": 0
                  },
                  {
                      "uid": "word-1-4",
                      "word": "button.",
                      "start_time": 1.36,
                      "end_time": 1.68,
                      "speakerId": 1,
                      "sentence_index": 0
                  }
              ]
          },
          {
              "uid": "sentence-2",
              "speakerId": 1,
              "words": [
                  {
                      "uid": "word-2-1",
                      "word": "This",
                      "start_time": 2.0,
                      "end_time": 2.3,
                      "speakerId": 1,
                      "sentence_index": 1
                  },
                  {
                      "uid": "word-2-2",
                      "word": "is",
                      "start_time": 2.3,
                      "end_time": 2.5,
                      "speakerId": 1,
                      "sentence_index": 1
                  },
                  {
                      "uid": "word-2-3",
                      "word": "important",
                      "start_time": 2.5,
                      "end_time": 3.0,
                      "speakerId": 1,
                      "sentence_index": 1
                  },
                  {
                      "uid": "word-2-4",
                      "word": "content.",
                      "start_time": 3.0,
                      "end_time": 3.5,
                      "speakerId": 1,
                      "sentence_index": 1
                  }
              ]
          }
      ],
      "highlight_duration": 10,
      "duration": 120,
      "language": "en"
  }'
  ```

  ```python Python theme={null}
  import requests

  url = "https://api.pictory.ai/pictoryapis/v2/transcription/highlights"
  headers = {
      "Authorization": "YOUR_API_KEY",
      "Content-Type": "application/json"
  }

  # Example edited transcript
  transcript = [
      {
          "uid": "sentence-1",
          "speakerId": 1,
          "words": [
              {
                  "uid": "word-1-1",
                  "word": "Click",
                  "start_time": 0.64,
                  "end_time": 0.96,
                  "speakerId": 1,
                  "sentence_index": 0
              },
              {
                  "uid": "word-1-2",
                  "word": "the",
                  "start_time": 0.96,
                  "end_time": 1.12,
                  "speakerId": 1,
                  "sentence_index": 0
              },
              {
                  "uid": "word-1-3",
                  "word": "play",
                  "start_time": 1.12,
                  "end_time": 1.36,
                  "speakerId": 1,
                  "sentence_index": 0
              }
          ]
      }
  ]

  payload = {
      "transcript": transcript,
      "highlight_duration": 10,
      "duration": 120,
      "language": "en",
      "webhook": "https://your-domain.com/api/webhooks/highlights"
  }

  response = requests.post(url, json=payload, headers=headers)
  data = response.json()

  if data.get("success"):
      print(f"Highlights Job ID: {data['data']['jobId']}")
      print("Highlights generation started successfully")
  else:
      print(f"Error: {data.get('message', 'Unknown error')}")
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.pictory.ai/pictoryapis/v2/transcription/highlights',
    {
      method: 'POST',
      headers: {
        'Authorization': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        transcript: [
          {
            uid: 'sentence-1',
            speakerId: 1,
            words: [
              {
                uid: 'word-1-1',
                word: 'Click',
                start_time: 0.64,
                end_time: 0.96,
                speakerId: 1,
                sentence_index: 0
              },
              {
                uid: 'word-1-2',
                word: 'the',
                start_time: 0.96,
                end_time: 1.12,
                speakerId: 1,
                sentence_index: 0
              }
            ]
          }
        ],
        highlight_duration: 10,
        duration: 120,
        language: 'en',
        webhook: 'https://your-domain.com/api/webhooks/highlights'
      })
    }
  );

  const data = await response.json();

  if (data.success) {
    console.log(`Highlights Job ID: ${data.data.jobId}`);
    console.log('Highlights generation started successfully');
  } else {
    console.log(`Error: ${data.message || 'Unknown error'}`);
  }
  ```

  ```php PHP theme={null}
  <?php
  $url = "https://api.pictory.ai/pictoryapis/v2/transcription/highlights";

  $transcript = [
      [
          'uid' => 'sentence-1',
          'speakerId' => 1,
          'words' => [
              [
                  'uid' => 'word-1-1',
                  'word' => 'Click',
                  'start_time' => 0.64,
                  'end_time' => 0.96,
                  'speakerId' => 1,
                  'sentence_index' => 0
              ],
              [
                  'uid' => 'word-1-2',
                  'word' => 'the',
                  'start_time' => 0.96,
                  'end_time' => 1.12,
                  'speakerId' => 1,
                  'sentence_index' => 0
              ]
          ]
      ]
  ];

  $payload = [
      'transcript' => $transcript,
      'highlight_duration' => 10,
      'duration' => 120,
      'language' => 'en',
      'webhook' => 'https://your-domain.com/api/webhooks/highlights'
  ];

  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'Authorization: YOUR_API_KEY',
      'Content-Type: application/json'
  ]);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

  $response = curl_exec($ch);
  $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);

  $data = json_decode($response, true);

  if ($httpCode === 200 && $data['success']) {
      echo "Highlights Job ID: " . $data['data']['jobId'] . "\n";
      echo "Highlights generation started successfully\n";
  } else {
      echo "Error: " . ($data['message'] ?? 'Unknown error') . "\n";
  }
  ?>
  ```
</CodeGroup>

***

## Common Use Cases

### 1. Generate Highlights from Edited Transcript

After manually correcting or enhancing a transcript:

```python theme={null}
import requests

def generate_highlights_from_edited_transcript(edited_transcript, duration, api_key):
    """
    Generate highlights after editing the transcript for accuracy
    """
    url = "https://api.pictory.ai/pictoryapis/v2/transcription/highlights"
    headers = {
        "Authorization": api_key,
        "Content-Type": "application/json"
    }

    payload = {
        "transcript": edited_transcript,
        "highlight_duration": 30,
        "duration": duration,
        "language": "en",
        "webhook": "https://your-domain.com/webhooks/highlights"
    }

    response = requests.post(url, json=payload, headers=headers)
    data = response.json()

    if data.get("success"):
        print(f"Highlights job created: {data['data']['jobId']}")
        return data['data']['jobId']
    else:
        print(f"Failed: {data.get('message')}")
        return None

# Use after editing transcript
edited_transcript = load_edited_transcript_from_database()
job_id = generate_highlights_from_edited_transcript(edited_transcript, 120, "YOUR_API_KEY")
```

### 2. Use Custom Transcript from External Source

When you have transcript data from a third-party service:

```javascript theme={null}
async function generateHighlightsFromExternalTranscript(externalTranscript) {
  // Convert external transcript format to Pictory format
  const pictoryTranscript = externalTranscript.sentences.map((sentence, index) => ({
    uid: `sentence-${index + 1}`,
    speakerId: sentence.speaker_id || 1,
    words: sentence.words.map((word, wordIndex) => ({
      uid: `word-${index + 1}-${wordIndex + 1}`,
      word: word.text,
      start_time: word.start,
      end_time: word.end,
      speakerId: sentence.speaker_id || 1,
      sentence_index: index
    }))
  }));

  const response = await fetch(
    'https://api.pictory.ai/pictoryapis/v2/transcription/highlights',
    {
      method: 'POST',
      headers: {
        'Authorization': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        transcript: pictoryTranscript,
        highlight_duration: 60,
        duration: externalTranscript.total_duration,
        language: 'en'
      })
    }
  );

  const data = await response.json();
  return data.success ? data.data.jobId : null;
}
```

***

## Usage Notes

<Note>
  **Async Processing**: This endpoint processes highlights asynchronously. You will receive a `jobId` immediately, and the actual highlights will be generated in the background.
</Note>

<Tip>
  **Webhook Notifications**: Provide a webhook URL to receive the completed highlights automatically. This is the recommended approach instead of polling.
</Tip>

<Note>
  **Transcript Format**: Ensure your transcript segments are in chronological order with accurate start and end times. The AI uses timing information to create seamless highlight clips.
</Note>

<Warning>
  **Duration Limits**: The `highlight_duration` should be shorter than your total transcript duration. The AI will select the most important segments that fit within the target duration.
</Warning>

***

## Best Practices

### Transcript Quality

1. **Accurate Timing**: Ensure start and end times are precise for smooth highlight transitions
2. **Complete Sentences**: Structure transcript at natural sentence boundaries for better context
3. **No Overlaps**: Word timings should not overlap
4. **Chronological Order**: Sentences and words must be ordered by time
5. **Unique IDs**: Use unique `uid` values for all sentences and words

### Duration Selection

1. **Platform Optimization**:
   * TikTok/Reels: 15-30 seconds
   * Instagram: 30-60 seconds
   * YouTube Shorts: 60 seconds
   * LinkedIn: 30-90 seconds

2. **Content Type**:
   * Product demos: 60-90 seconds
   * Testimonials: 30-45 seconds
   * Educational: 45-60 seconds

### Webhook Implementation

1. **Return 200 OK Quickly**: Process the webhook payload asynchronously to avoid timeouts
2. **Implement Retry Logic**: Webhooks may be retried if they fail
3. **Validate Signatures**: Implement webhook signature validation for security
4. **Log All Webhooks**: Keep logs for debugging and audit trails

***

## Related Endpoints

* [Generate Highlights from Transcription Job](/api-reference/transcription/generate-highlights-from-job): Simpler option if you have not edited the transcript
* [Video Transcription API](/api-reference/transcription/video-transcription) - Generate the initial transcript
* [Get Job by ID](/api-reference/jobs/get-transcription-job-by-id) - Check job status and retrieve results
