# AI Detection Source: https://docs.pangram.com/api-reference/ai-detection POST https://text.external-api.pangram.com/task Detect AI-generated and AI-assisted text using the async inference API For more information on billing units and pricing, check our [pricing page for developers](https://www.pangram.com/pricing?category=developers). Current The current AI detection API creates an async task and returns a task ID. Poll the task endpoint until it reaches `STAGE_SUCCESS` or `STAGE_FAILED`. Use the [Bulk API](/api-reference/bulk-api) when you need to analyze many texts as one asynchronous job. Use [`GET /models`](/api-reference/models) to discover the selectors available to your API key. The REST API temporarily accepts an omitted `model` for backward compatibility and resolves it to `"default"`. New integrations should always send a selector explicitly. ## POST /task Create an async AI detection task. ``` POST https://text.external-api.pangram.com/task ``` ### Request The input text to analyze. A model selector returned by [`GET /models`](/api-reference/models). Whether to include a public dashboard link in the completed response. ### Response The ID of the async inference task. ### Example ```bash cURL theme={null} curl -X POST https://text.external-api.pangram.com/task \ -H "Content-Type: application/json" \ -H "x-api-key: your_api_key_here" \ -d '{ "text": "AI-assisted passage. Human passage.", "model": "pangram-4", "public_dashboard_link": false }' ``` ```python Python SDK theme={null} from pangram import Pangram pangram_client = Pangram() result = pangram_client.predict( "AI-assisted passage. Human passage.", model="pangram-4", ) ``` **Example Response** ```json theme={null} { "task_id": "123e4567-e89b-12d3-a456-426614174000" } ``` ### Model selection errors | Status Code | Description | | -------------------------- | --------------------------------------------------- | | `403 Forbidden` | The requested model is not enabled for the API key. | | `422 Unprocessable Entity` | The model selector is malformed or unknown. | | `503 Service Unavailable` | The requested model is temporarily unavailable. | *** ## GET /task/ Fetch the current status or completed result for an AI detection task. ``` GET https://text.external-api.pangram.com/task/{task_id} ``` ### Request The task ID returned by `POST /task`. ### Response The ID of the async inference task. Present while the task is in progress. Current task stage. Terminal stages are `STAGE_SUCCESS` and `STAGE_FAILED`. The analyzed text returned by the model. Pangram 4 may normalize the submitted text before inference; window offsets refer to this returned value. Present on success. The API version identifier (e.g., `"4.0"` for Pangram 4). Present on success. Classification headline summarizing the result. Present on success. Long-form prediction string describing the classification. Present on success. Short-form prediction string. Pangram 4 returns `"AI"`, `"Human"`, or `"Mixed"`. Present on success. Fraction of text classified as AI-written (0.0–1.0). Present on success. Fraction of text classified as AI-assisted (0.0–1.0). Present on success. Fraction of text classified as human-written (0.0–1.0). Present on success. Number of text segments classified as AI. Present on success. Number of text segments classified as AI-assisted. Present on success. Number of text segments classified as human. Present on success. A link to the dashboard page containing the full classification result. Present on success when `public_dashboard_link` is `true`. List of text segments (windows) analyzed individually. Present on success. The window text. Descriptive classification label. Pangram 4 returns `"AI-Generated"`, `"AI-Assisted"`, or `"Human Written"`. AI assistance score detailing the level of AI assistance (0.0–1.0). Confidence level for the classification (`"High"`, `"Medium"`, `"Low"`). Starting character index in the returned top-level `text`. End-exclusive character index in the returned top-level `text`. Number of words in the window. Token length of the window. Whether Pangram 4's humanizer head classified the window as humanized. Present on every Pangram 4 window. Pangram 4 humanizer-head score from 0.0–1.0. Present on every Pangram 4 window. ### Example ```bash cURL theme={null} curl -X GET https://text.external-api.pangram.com/task/123e4567-e89b-12d3-a456-426614174000 \ -H "x-api-key: your_api_key_here" ``` **In-Progress Response** ```json theme={null} { "task_id": "123e4567-e89b-12d3-a456-426614174000", "stage": "STAGE_PREPROCESSING" } ``` **Success Response** This example shows a Pangram 4 result. Pangram 4 returns `version: "4.0"`, uses `"AI-Assisted"` instead of lightly or moderately assisted window labels, and keeps `confidence` as `"Low"`, `"Medium"`, or `"High"`. ```json theme={null} { "stage": "STAGE_SUCCESS", "text": "AI-assisted passage. Human passage.", "version": "4.0", "headline": "AI Assisted", "prediction": "We believe that this text is a mix of AI-assisted and human-written content.", "prediction_short": "Mixed", "fraction_ai": 0.0, "fraction_ai_assisted": 0.6, "fraction_human": 0.4, "num_ai_segments": 0, "num_ai_assisted_segments": 1, "num_human_segments": 1, "windows": [ { "text": "AI-assisted passage. ", "label": "AI-Assisted", "ai_assistance_score": 0.55, "confidence": "High", "start_index": 0, "end_index": 21, "word_count": 2, "token_length": 5, "is_humanized": true, "humanizer_score": 0.91 }, { "text": "Human passage.", "label": "Human Written", "ai_assistance_score": 0.02, "confidence": "Medium", "start_index": 21, "end_index": 35, "word_count": 2, "token_length": 4, "is_humanized": false, "humanizer_score": 0.0 } ] } ``` **Failed Response** ```json theme={null} { "stage": "STAGE_FAILED", "text": "", "version": "", "headline": "preprocessing: Input text contains no valid text after preprocessing", "prediction": "", "prediction_short": "", "fraction_ai": 0.0, "fraction_ai_assisted": 0.0, "fraction_human": 0.0, "num_ai_segments": 0, "num_ai_assisted_segments": 0, "num_human_segments": 0, "windows": [] } ``` # Bulk API Source: https://docs.pangram.com/api-reference/bulk-api POST https://text.external-api.pangram.com/bulk Submit asynchronous AI detection jobs for many texts For more information on billing units and pricing, check our [pricing page for developers](https://www.pangram.com/pricing?category=developers). Current The Bulk API queues many AI detection inputs as one asynchronous job. Submit the job with `POST /bulk`, poll `GET /bulk/{bulk_id}`, then page through item metadata or results. Completion time depends on the number and length of submitted items and current system load. Use `GET /bulk/{bulk_id}` to monitor progress. Bulk jobs use the same base URL and API key authentication as the AI detection task API: ```text theme={null} https://text.external-api.pangram.com ``` Terminal bulk statuses are `succeeded`, `failed`, and `partial`. Bulk metadata and results are retained for 48 hours after the job reaches a terminal status. Timestamps are returned as Unix epoch seconds encoded as strings, such as `"1760000000.0"`. Treat them as UTC instants when converting to a date-time value. The launch bulk limit is 1,000 billable units per request. A billable unit is one started word block per valid item — 100 words for Pangram 4, or 1,000 words for Pangram 3 — with a minimum of one unit per item. There is no separate item-count limit, but normal request-body limits still apply. Requests over the current bulk limit return `413 Payload Too Large`. One `model` applies to the entire bulk job; per-item model selectors are not supported. Use [`GET /models`](/api-reference/models) to discover the selectors available to your API key. The REST API temporarily accepts an omitted selector for backward compatibility and resolves it to `"default"`. New integrations should send it explicitly. ## POST /bulk Create a bulk AI detection job. ``` POST https://text.external-api.pangram.com/bulk ``` ### Request Provide exactly one of `items` or `text`. Valid request bodies use either a plain `text` list: ```json theme={null} {"text": ["First text", "Second text"], "model": "pangram-4"} ``` Or an `items` list when you want customer IDs returned with status and results: ```json theme={null} {"items": [{"id": "row-001", "text": "First text"}], "model": "pangram-4"} ``` Do not include both `text` and `items` in the same request. Item `id` values are optional, but must be unique when provided. List of item objects. Each item must include `text` and may include a unique customer-defined `id`. List of input text strings. Use this simpler shape when you do not need customer item IDs. A selector returned by [`GET /models`](/api-reference/models). Applies to every item in the job. Optional customer-defined item ID. IDs must be unique within the bulk request. The input text to analyze. ### Response Returns `202 Accepted`. The ID of the bulk job. Initial status. Usually `queued`; returns `failed` if every item failed immediate validation. Total number of submitted items. Items accepted for processing. Each item includes `index`, optional `id`, and `task_id`. Items that failed immediate validation. Each item includes `index`, optional `id`, `task_id: null`, `stage`, and `error`. ### Example ```bash cURL theme={null} curl -X POST https://text.external-api.pangram.com/bulk \ -H "Content-Type: application/json" \ -H "x-api-key: your_api_key_here" \ -d '{ "items": [ {"id": "row-001", "text": "First text to analyze"}, {"id": "row-002", "text": "Second text to analyze"} ], "model": "pangram-4" }' ``` ```python Python SDK theme={null} from pangram import Pangram client = Pangram() bulk = client.submit_bulk( items=[ {"id": "row-001", "text": "First text to analyze"}, {"id": "row-002", "text": "Second text to analyze"}, ], model="pangram-4", ) bulk_id = bulk["bulk_id"] ``` **Example Response** ```json theme={null} { "bulk_id": "blk_123", "status": "queued", "total_items": 2, "accepted_items": [ { "index": 0, "id": "row-001", "task_id": "123e4567-e89b-12d3-a456-426614174000" }, { "index": 1, "id": "row-002", "task_id": "223e4567-e89b-12d3-a456-426614174000" } ], "failed_items": [] } ``` *** ## GET /bulk/ Fetch the current status and counters for a bulk job. ``` GET https://text.external-api.pangram.com/bulk/{bulk_id} ``` ### Request The bulk job ID returned by `POST /bulk`. ### Response The ID of the bulk job. One of `queued`, `running`, `succeeded`, `failed`, or `partial`. Total number of submitted items. Number of items accepted for processing. Number of items that completed successfully. Number of items that failed. Job creation timestamp as Unix epoch seconds encoded as a string. Job completion timestamp as Unix epoch seconds encoded as a string. `null` while the job is not terminal. **Example Response** ```json theme={null} { "bulk_id": "blk_123", "status": "partial", "total_items": 3, "accepted": 2, "succeeded": 2, "failed": 1, "created_at": "1760000000.0", "completed_at": "1760000030.0" } ``` *** ## Status values | Status | Description | | ----------- | ------------------------------------------------------------------------------------- | | `queued` | The job was accepted, but no accepted item has started processing yet. | | `running` | At least one accepted item is in progress and the job is not terminal. | | `succeeded` | Every submitted item completed successfully. | | `failed` | Every submitted item failed, including immediate validation failures. | | `partial` | Every submitted item is terminal, with at least one success and at least one failure. | ## GET /bulk//items Fetch paginated item metadata for a bulk job. ``` GET https://text.external-api.pangram.com/bulk/{bulk_id}/items?offset=0&limit=100 ``` ### Request The bulk job ID returned by `POST /bulk`. Zero-based item offset. Maximum number of items to return. The maximum is `1000`. ### Response The ID of the bulk job. The returned page offset. The returned page limit. Total number of submitted items. Item metadata. Each item includes `index`, optional `id`, `task_id`, `stage`, and optional `error`. **Example Response** ```json theme={null} { "bulk_id": "blk_123", "offset": 0, "limit": 100, "total_items": 2, "items": [ { "index": 0, "id": "row-001", "task_id": "123e4567-e89b-12d3-a456-426614174000", "stage": "STAGE_SUCCESS", "error": null }, { "index": 1, "id": "row-002", "task_id": null, "stage": "STAGE_FAILED", "error": "Text must contain at least one valid token" } ] } ``` *** ## GET /bulk//results Fetch paginated results for a bulk job. ``` GET https://text.external-api.pangram.com/bulk/{bulk_id}/results?offset=0&limit=100 ``` ### Request The bulk job ID returned by `POST /bulk`. Zero-based item offset. Maximum number of items to return. The maximum is `1000`. ### Response The ID of the bulk job. The returned page offset. The returned page limit. Total number of submitted items. Result items for successful or in-progress work. Successful completed items include `result`; in-progress items have `result: null`. Failed item metadata for the requested page. **Example Response** ```json theme={null} { "bulk_id": "blk_123", "offset": 0, "limit": 100, "total_items": 2, "items": [ { "index": 0, "id": "row-001", "task_id": "123e4567-e89b-12d3-a456-426614174000", "stage": "STAGE_SUCCESS", "error": null, "result": { "stage": "STAGE_SUCCESS", "text": "First text to analyze", "version": "4.0", "prediction": "We believe that this entire text is human-written.", "prediction_short": "Human", "fraction_ai": 0.0, "fraction_ai_assisted": 0.0, "fraction_human": 1.0, "headline": "Human Written", "num_ai_segments": 0, "num_ai_assisted_segments": 0, "num_human_segments": 1, "windows": [ { "text": "First text to analyze", "label": "Human Written", "ai_assistance_score": 0.02, "confidence": "High", "start_index": 0, "end_index": 21, "word_count": 4, "token_length": 5, "is_humanized": false, "humanizer_score": 0.0 } ] } } ], "failed_items": [ { "index": 1, "id": "row-002", "task_id": null, "stage": "STAGE_FAILED", "error": "Text must contain at least one valid token" } ] } ``` ## Errors | Status Code | Description | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `401 Unauthorized` | The `x-api-key` is missing or invalid. | | `402 Payment Required` | The account has insufficient credits. | | `403 Forbidden` | The requested model is not enabled for the API key, or the API key does not own the requested bulk job. | | `404 Not Found` | The requested bulk job does not exist. | | `413 Payload Too Large` | The bulk request exceeds the maximum billable units. | | `422 Unprocessable Entity` | The request is empty, contains both `items` and `text`, includes duplicate item IDs, uses an invalid model selector, or otherwise fails validation. | | `500 Internal Server Error` | There was an error processing the request. | | `503 Service Unavailable` | The requested model is temporarily unavailable. | # Deprecated Endpoints Source: https://docs.pangram.com/api-reference/deprecated-endpoints Legacy AI detection endpoints replaced by the async inference API For more information on billing units and pricing, check our [pricing page for developers](https://www.pangram.com/pricing?category=developers). All endpoints on this page are legacy AI detection endpoints. Use the current [async AI detection API](/api-reference/ai-detection) for single inputs or the [Bulk API](/api-reference/bulk-api) for many inputs. ## Synchronous V3 Endpoint Deprecated Legacy ### POST /v3 ``` POST https://text.api.pangram.com/v3 ``` Synchronous V3 classification endpoint. Use `POST /task` and `GET /task/{task_id}` on `https://text.external-api.pangram.com` instead. **Request Body** The input text to analyze. Whether to include a public dashboard link in the response. **Response** Returns the completed AI detection result directly, including `prediction`, `prediction_short`, authorship fractions, segment counts, and `windows`. *** ## Root Endpoint Deprecated Legacy ### POST / ``` POST https://text.api.pangram.com ``` Single text classification returning an AI likelihood score. **Request Body** The input text to classify. If `true`, return a list of the most indicative AI sentences. **Response** Classification score from 0.0 (human) to 1.0 (AI). The classified text. A string representing the classification. List of the most indicative AI sentences. Only present when `return_ai_sentences` is `true`. **Example Response** ```json theme={null} { "text": "The text to analyze", "prediction": "Likely AI", "ai_likelihood": 0.92 } ``` *** ## Batch Endpoint Deprecated Legacy ### POST / ``` POST https://text-batch.api.pangram.com ``` Classify multiple texts in a single request. Use the current [Bulk API](/api-reference/bulk-api) instead. **Request Body** An array of input texts to classify. **Response** The classification results as a list. Each item contains `text`, `ai_likelihood`, and `prediction`. **Example Response** ```json theme={null} { "responses": [ { "text": "The first text to analyze", "prediction": "Likely AI", "ai_likelihood": 0.92 }, { "text": "The second text to analyze", "prediction": "Possibly AI", "ai_likelihood": 0.58 } ] } ``` *** ## Sliding Window Endpoint Deprecated Legacy ### POST / ``` POST https://text-sliding.api.pangram.com ``` Classify a long document using a sliding window across the full text. **Request Body** The input text to segment into windows and classify. If `true`, return a list of the most indicative AI sentences. **Response** The classified text. Classification score from 0.0 (human) to 1.0 (AI). Maximum AI likelihood score among all windows. Average AI likelihood score among all windows. A string representing the classification. Short classification string (`"AI"`, `"Human"`, `"Mixed"`). Fraction of windows classified as AI. List of windows and their individual classifications. **Example Response** ```json theme={null} { "text": "Extremely long text.", "prediction": "Highly likely AI", "ai_likelihood": 1.0, "max_ai_likelihood": 1.0, "avg_ai_likelihood": 0.6, "fraction_ai_content": 0.5, "windows": [ { "text": "Extremely long", "ai_likelihood": 1.0, "prediction": "Highly likely AI" }, { "text": "long text.", "ai_likelihood": 0.2, "prediction": "Unlikely AI" } ] } ``` *** ## Dashboard Endpoint Deprecated Legacy ### POST / ``` POST https://dashboard-text.api.pangram.com ``` Classify text and return a link to a dashboard page with the full result. **Request Body** The input text to classify. **Response** Classification score from 0.0 (human) to 1.0 (AI). A string representing the classification. Short classification string (`"AI"`, `"Human"`, `"Mixed"`). A link to the dashboard page containing the full classification result. Fraction of windows classified as AI. Maximum AI likelihood score among all windows. Average AI likelihood score among all windows. List of windows and their individual classifications. **Example Response** ```json theme={null} { "text": "Extremely long text.", "prediction": "Highly likely AI", "ai_likelihood": 1.0, "dashboard_link": "https://www.pangram.com/history/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "max_ai_likelihood": 1.0, "avg_ai_likelihood": 0.6, "fraction_ai_content": 0.5, "windows": [ { "text": "Extremely long", "ai_likelihood": 1.0, "prediction": "Highly likely AI" }, { "text": "long text.", "ai_likelihood": 0.2, "prediction": "Unlikely AI" } ] } ``` *** ## Extended Endpoint Deprecated Legacy ### POST / ``` POST https://text-extended.api.pangram.com ``` Extended analysis with adaptive boundaries and windowed results. **Request Body** The input text to classify with extended analysis. Enable dashboard integration. Control visibility in dashboard. **Response** The input text that was analyzed. Weighted average AI likelihood score across all windows. Maximum AI likelihood score among all windows. Long-form prediction string representing the classification. Short-form prediction string (`"AI"`, `"Human"`, `"Mixed"`). Classification headline summarizing the result. List of text segments analyzed individually. Each window contains `text`, `ai_likelihood`, `label`, `confidence`, `start_index`, `end_index`, and `word_count`. AI likelihood scores for each window (list of values from 0.0 to 1.0). Indices indicating the position of each window in the original text (list of `[start_char_index, end_char_index]`). Fraction of text classified as human-written (0.0–1.0). Fraction of text classified as AI-written (0.0–1.0). Fraction of text classified as mixed content (0.0–1.0). Additional metadata about the analysis. Analysis version identifier (`"adaptive_boundaries"`). Dashboard link. Only present when `dashboard` is `true`. `is_public` controls visibility. **Example Response** ```json theme={null} { "text": "The text to analyze with extended classification", "avg_ai_likelihood": 0.75, "max_ai_likelihood": 0.92, "prediction": "Primarily AI-generated, or heavily AI-assisted", "prediction_short": "AI", "headline": "AI Detected", "windows": [ { "text": "The text to analyze", "ai_likelihood": 0.85, "label": "AI", "confidence": "Medium", "start_index": 0, "end_index": 19, "word_count": 4 }, { "text": "with extended classification", "ai_likelihood": 0.65, "label": "AI", "confidence": "Low", "start_index": 20, "end_index": 47, "word_count": 3 } ], "window_likelihoods": [0.85, 0.65], "window_indices": [[0, 19], [20, 47]], "fraction_human": 0.25, "fraction_ai": 0.70, "fraction_mixed": 0.05, "metadata": { "request_id": "123e4567-e89b-12d3-a456-426614174000" }, "version": "adaptive_boundaries", "dashboard_link": "https://www.pangram.com/history/123e4567-e89b-12d3-a456-426614174000" } ``` # File Upload Source: https://docs.pangram.com/api-reference/file-external openapi/file-upload.json POST / Upload files for AI detection and receive dashboard links For more information on billing units and pricing, check our [pricing page for developers](https://www.pangram.com/pricing?category=developers). Current File uploads accept documents as multipart form data and return per-file results. Use them when you want Pangram to extract text from files and create dashboard-backed AI detection results. ## POST / Upload one or more files for AI detection. ``` POST https://file-external.api.pangram.com ``` This endpoint must receive `multipart/form-data` with a form field named `files`. Requests without that field return `422 Unprocessable Entity` with `Field required` for `body.files`. File prediction currently uses Pangram's default model. This endpoint does not accept a `model` field. ### Request Send the request as `multipart/form-data`. When using cURL, do not set the `Content-Type` header yourself. The `-F` flags add the multipart boundary automatically. | Field | Type | Required | Description | | ----------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------- | | `files` | file\[] | Yes | Files to analyze. Include the `files` form field once per uploaded file. | | `public_dashboard_link` | boolean | No | Whether to create and return a public dashboard link for each uploaded file. Defaults to `false`. | ### Response Returns a JSON array with one result object per uploaded file. | Field | Type | Description | | ----------------------- | ------ | ------------------------------------------------------------------------------------------- | | `public_dashboard_link` | string | Public dashboard URL for the uploaded file. Present when `public_dashboard_link` is `true`. | ### Example ```bash cURL theme={null} curl -s -X POST https://file-external.api.pangram.com \ -H "x-api-key: $PANGRAM_API_KEY" \ -F "files=@modeling/deployments/test/test_document.docx" \ -F "public_dashboard_link=true" ``` To upload multiple files, repeat the `files` form field: ```bash cURL theme={null} curl -s -X POST https://file-external.api.pangram.com \ -H "x-api-key: $PANGRAM_API_KEY" \ -F "files=@path/to/first.docx" \ -F "files=@path/to/second.pdf" \ -F "public_dashboard_link=true" ``` **Example Response** ```json theme={null} [ { "public_dashboard_link": "https://www.pangram.com/history/123e4567-e89b-12d3-a456-426614174000" } ] ``` To print only the dashboard link: ```bash theme={null} curl -s -X POST https://file-external.api.pangram.com \ -H "x-api-key: $PANGRAM_API_KEY" \ -F "files=@modeling/deployments/test/test_document.docx" \ -F "public_dashboard_link=true" \ | jq -r '.[0].public_dashboard_link' ``` ## Errors | Status Code | Description | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | The multipart request is missing a file or includes invalid form data. | | `401 Unauthorized` | The `x-api-key` is missing or invalid. | | `402 Payment Required` | The account has insufficient credits. | | `413 Payload Too Large` | The upload exceeds the maximum supported file size. | | `415 Unsupported Media Type` | The uploaded file type is not supported. | | `422 Unprocessable Entity` | The `files` field is missing, the form data is invalid, or Pangram could not extract valid text from the uploaded file. | | `500 Internal Server Error` | There was an error processing the upload. | # API Overview Source: https://docs.pangram.com/api-reference/introduction Base URL, authentication, and error handling for the Pangram REST API For more information on billing units and pricing, check our [pricing page for developers](https://www.pangram.com/pricing?category=developers). ## Base URLs AI detection and bulk AI detection use the following base URL: ``` https://text.external-api.pangram.com ``` File uploads use the following base URL: ``` https://file-external.api.pangram.com ``` The plagiarism detection endpoint uses a separate base URL: ``` https://plagiarism.api.pangram.com ``` ## Authentication All API requests must include your API key in the `x-api-key` header. ```bash theme={null} curl -X POST https://text.external-api.pangram.com/task \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"text": "Your text here", "model": "default"}' ``` ```python theme={null} import requests response = requests.post( "https://text.external-api.pangram.com/task", headers={ "Content-Type": "application/json", "x-api-key": "", }, json={"text": "Your text here", "model": "default"}, ) task_id = response.json()["task_id"] result = requests.get( f"https://text.external-api.pangram.com/task/{task_id}", headers={"x-api-key": ""}, ) ``` ```javascript theme={null} const submitResponse = await fetch("https://text.external-api.pangram.com/task", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": "" }, body: JSON.stringify({ text: "Your text here", model: "default" }) }); const { task_id } = await submitResponse.json(); const resultResponse = await fetch(`https://text.external-api.pangram.com/task/${task_id}`, { headers: { "x-api-key": "" } }); ``` ## Model Discovery Call [`GET /models`](/api-reference/models) to retrieve the ordered model selectors available to your API key. The catalog is entitlement- and availability-aware; do not hard-code it or assume every account sees the same values. Pass one returned selector as `model` when creating a text or bulk job. One selector applies to the entire request. New integrations should always send it explicitly. ## Async Task Flow Submit text with `POST /task`, then poll `GET /task/{task_id}` until the returned `stage` is `STAGE_SUCCESS` or `STAGE_FAILED`. ## Bulk Flow Submit many texts with `POST /bulk`, poll `GET /bulk/{bulk_id}` until the returned `status` is `succeeded`, `failed`, or `partial`, then page through `GET /bulk/{bulk_id}/results`. Bulk completion time depends on the number and length of submitted items and current system load. Use `GET /bulk/{bulk_id}` to monitor progress. Bulk metadata and results are retained for 48 hours after terminal completion. Bulk `created_at` and `completed_at` values are Unix epoch seconds encoded as strings. ## File Upload Flow Submit documents as `multipart/form-data` to `https://file-external.api.pangram.com`. Include one or more `files` fields and set `public_dashboard_link=true` when you need a shareable result link. ## Error Codes | Status Code | Description | | --------------------------- | --------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | The request body is not properly formatted. | | `401 Unauthorized` | The `x-api-key` is missing or invalid. | | `402 Payment Required` | The account has insufficient credits. | | `403 Forbidden` | The requested model is not enabled for the API key, or the API key does not own the requested task or bulk job. | | `404 Not Found` | The requested task or bulk job does not exist. | | `413 Payload Too Large` | The bulk request exceeds the maximum billable units. | | `422 Unprocessable Entity` | The input text or model selector is invalid. | | `429 Too Many Requests` | The API key exceeds its configured rate limit. | | `500 Internal Server Error` | There was an error processing the request. | | `503 Service Unavailable` | The selected model is temporarily unavailable. | If you are running into errors, please reach out at [support@pangram.com](mailto:support@pangram.com). # Models Source: https://docs.pangram.com/api-reference/models GET https://text.external-api.pangram.com/models Discover the AI detection models available to your API key Current Use the Models API to discover the model selectors your API key can currently use. The catalog reflects both your account's entitlements and current model availability, so do not hard-code it or assume every API key sees the same models. Preserve the order returned by the server. ## GET /models ``` GET https://text.external-api.pangram.com/models ``` ### Response Ordered model selectors currently available to the authenticated API key. ### Example ```bash cURL theme={null} curl -X GET https://text.external-api.pangram.com/models \ -H "x-api-key: $PANGRAM_API_KEY" ``` ```python Python SDK theme={null} from pangram import Pangram client = Pangram() available_models = client.list_models() ``` **Example Response** ```json theme={null} { "models": [ "default", "pangram-4" ] } ``` Use one of the returned values as the request-wide `model` on [`POST /task`](/api-reference/ai-detection) or [`POST /bulk`](/api-reference/bulk-api). The `default` selector follows Pangram's current default model without pinning your integration to a numbered generation. ## Errors | Status Code | Description | | --------------------------- | ----------------------------------------- | | `401 Unauthorized` | The `x-api-key` is missing or invalid. | | `500 Internal Server Error` | The model catalog could not be retrieved. | # Plagiarism Detection Source: https://docs.pangram.com/api-reference/plagiarism-detection POST https://plagiarism.api.pangram.com Check text for potential plagiarism against online content For more information on billing units and pricing, check our [pricing page for developers](https://www.pangram.com/pricing?category=developers). ## POST / Check text for potential plagiarism by comparing it against a vast database of online content. ``` POST https://plagiarism.api.pangram.com ``` ### Request The input text to check for plagiarism. ### Response The input text that was checked. Whether plagiarism was detected in the text. A list of detected plagiarized content, including source URLs and matched text. The URL of the source where the match was found. The text that matched the source. Similarity score for the match (0.0–1.0). Total number of sentences in the input text. Number of sentences that were detected as plagiarized. Percentage of the text that was detected as plagiarized. ### Example ```bash cURL theme={null} curl -X POST https://plagiarism.api.pangram.com \ -H "Content-Type: application/json" \ -H "x-api-key: your_api_key_here" \ -d '{ "text": "The text to check for plagiarism" }' ``` ```python Python theme={null} from pangram import Pangram pangram_client = Pangram() result = pangram_client.check_plagiarism("The text to check for plagiarism") ``` **Example Response** ```json theme={null} { "text": "The text to check for plagiarism", "plagiarism_detected": true, "plagiarized_content": [ { "source_url": "https://example.com/source", "matched_text": "The text to check for plagiarism", "similarity_score": 0.95 } ], "total_sentences": 1, "plagiarized_sentences": 1, "percent_plagiarized": 100.0 } ``` # Pangram Labs Documentation Source: https://docs.pangram.com/index Detect AI-generated text with a simple REST API or Python integration ## Welcome to Pangram Labs Pangram Labs provides AI-generated text detection and plagiarism checking through a simple REST API and Python SDK. Analyze text for AI authorship, detect AI-assisted writing, and check for plagiarism. Install the Python SDK and make your first prediction in minutes. Full reference for the Pangram Python client library. Integrate directly with the Pangram REST API. Detailed endpoint reference for AI text detection. Submit asynchronous AI detection jobs for many texts. # Python Quickstart Source: https://docs.pangram.com/quickstart Get started with the Pangram Python SDK in minutes ```bash theme={null} pip install pangram-sdk ``` You can provide your API key in two ways. **Option 1: Environment variable** ```bash theme={null} export PANGRAM_API_KEY= ``` **Option 2: Pass directly to the constructor** ```python theme={null} from pangram import Pangram pangram_client = Pangram(api_key="your-api-key") ``` Model availability is specific to your API key. Retrieve the current catalog instead of hard-coding it. ```python theme={null} available_models = pangram_client.list_models() print(available_models) # e.g., ["default", "pangram-4"] ``` Use one returned value as the keyword-only `model` argument on text and bulk requests. ### Main prediction Returns detailed analysis with AI-assistance detection and segment-level metrics. The SDK submits an async inference task and waits for the completed result before returning. ```python theme={null} from pangram import Pangram pangram_client = Pangram() result = pangram_client.predict(text, model="pangram-4") stage = result['stage'] # "STAGE_SUCCESS" after predict() completes. version = result['version'] # "4.0" for Pangram 4. # Analysis with AI-assistance detection. fraction_ai = result['fraction_ai'] fraction_ai_assisted = result['fraction_ai_assisted'] fraction_human = result['fraction_human'] num_ai_segments = result['num_ai_segments'] # Access individual window classifications for window in result['windows']: label = window['label'] ai_assistance_score = window['ai_assistance_score'] confidence = window['confidence'] is_humanized = window['is_humanized'] humanizer_score = window['humanizer_score'] ``` ### Dashboard link ```python theme={null} from pangram import Pangram pangram_client = Pangram() result = pangram_client.predict( text, public_dashboard_link=True, model="pangram-4", ) dashboard_link = result['dashboard_link'] ``` Use the Bulk API for asynchronous AI detection across many inputs. Submit the job, wait for a terminal status, then fetch results. Completion time depends on the number and length of submitted items and current system load. Use `get_bulk_status()` or `wait_for_bulk()` to monitor progress. ```python theme={null} from pangram import Pangram pangram_client = Pangram() bulk = pangram_client.submit_bulk( items=[ {"id": "row-001", "text": "First text to analyze"}, {"id": "row-002", "text": "Second text to analyze"}, ], model="pangram-4", ) bulk_id = bulk["bulk_id"] status = pangram_client.wait_for_bulk(bulk_id, poll_interval=2) results = pangram_client.get_bulk_results(bulk_id) for item in results["items"]: if item["result"] is not None: print(item["id"], item["result"]["prediction_short"]) for failed in results["failed_items"]: print(failed["id"], failed["error"]) ``` For large jobs, process one results page at a time: ```python theme={null} offset = 0 limit = 1000 while True: page = pangram_client.get_bulk_results_page(bulk_id, offset=offset, limit=limit) for item in page["items"]: process(item) for failed in page["failed_items"]: handle_failure(failed) offset += limit if offset >= page["total_items"]: break ``` The plagiarism detection API checks text against a vast database of online content: ```python theme={null} from pangram import Pangram pangram_client = Pangram() text = "Text to check for plagiarism" result = pangram_client.check_plagiarism(text) if result['plagiarism_detected']: print(f"Plagiarism detected! {result['percent_plagiarized']}% of the text may be plagiarized.") for content in result['plagiarized_content']: print(f"Found match at {content['source_url']}") print(f"Matched text: {content['matched_text']}") ``` The response includes: * Whether plagiarism was detected * List of plagiarized content with source URLs * Total number of sentences checked * List of plagiarized sentences * Percentage of text that was plagiarized For backward compatibility, the SDK temporarily permits omitted model selection, preserves the existing wire payload, and emits a `DeprecationWarning`. Pass `model="default"` or another value from `list_models()` in new code. The argument will be required after September 30, 2026. ## Deprecated Methods The following SDK compatibility methods are deprecated and may be removed on August 1, 2026. Use `predict()` for one-off calls or `submit_bulk()` for asynchronous bulk jobs. * `predict_short()` — Forwards to `predict()` and returns the current async result schema * `batch_predict()` — Calls `predict()` once per input text # REST API Quickstart Source: https://docs.pangram.com/quickstart-rest Get started with the Pangram REST API using cURL All requests require your API key in the `x-api-key` header. ```bash theme={null} export PANGRAM_API_KEY= ``` Retrieve the model selectors enabled for your API key. ```bash theme={null} curl -X GET https://text.external-api.pangram.com/models \ -H "x-api-key: $PANGRAM_API_KEY" ``` The response is entitlement- and availability-aware: ```json theme={null} { "models": ["default", "pangram-4"] } ``` Pangram AI detection uses an async task API. Submit text to create a task. ```bash theme={null} curl -X POST https://text.external-api.pangram.com/task \ -H "Content-Type: application/json" \ -H "x-api-key: $PANGRAM_API_KEY" \ -d '{ "text": "The text to analyze", "model": "pangram-4", "public_dashboard_link": false }' ``` **Example Response** ```json theme={null} { "task_id": "123e4567-e89b-12d3-a456-426614174000" } ``` Poll the task endpoint until `stage` is `STAGE_SUCCESS` or `STAGE_FAILED`. ```bash theme={null} curl -X GET https://text.external-api.pangram.com/task/123e4567-e89b-12d3-a456-426614174000 \ -H "x-api-key: $PANGRAM_API_KEY" ``` **Example Success Response** ```json theme={null} { "stage": "STAGE_SUCCESS", "text": "The text to analyze", "version": "4.0", "headline": "Human Written", "prediction": "We believe that this entire text is human-written.", "prediction_short": "Human", "fraction_ai": 0.0, "fraction_ai_assisted": 0.0, "fraction_human": 1.0, "num_ai_segments": 0, "num_ai_assisted_segments": 0, "num_human_segments": 1, "windows": [ { "text": "The text to analyze", "label": "Human Written", "ai_assistance_score": 0.02, "confidence": "High", "start_index": 0, "end_index": 19, "word_count": 4, "token_length": 5, "is_humanized": false, "humanizer_score": 0.0 } ] } ``` Key response fields: * `stage` — terminal task stage for completed results * `fraction_ai` / `fraction_ai_assisted` / `fraction_human` — breakdown of text by authorship * `windows` — segment-level classifications with confidence scores * `headline` — summary classification, such as `"AI Detected"` or `"Human Written"` * `is_humanized` / `humanizer_score` — Pangram 4 humanizer-head output on every window Pass `public_dashboard_link: true` when submitting the task to get a shareable link in the completed result. ```bash theme={null} curl -X POST https://text.external-api.pangram.com/task \ -H "Content-Type: application/json" \ -H "x-api-key: $PANGRAM_API_KEY" \ -d '{ "text": "The text to analyze", "model": "pangram-4", "public_dashboard_link": true }' ``` Use `POST /bulk` for asynchronous AI detection across many inputs. ```bash theme={null} curl -X POST https://text.external-api.pangram.com/bulk \ -H "Content-Type: application/json" \ -H "x-api-key: $PANGRAM_API_KEY" \ -d '{ "items": [ {"id": "row-001", "text": "First text to analyze"}, {"id": "row-002", "text": "Second text to analyze"} ], "model": "pangram-4" }' ``` **Example Response** ```json theme={null} { "bulk_id": "blk_123", "status": "queued", "total_items": 2, "accepted_items": [ {"index": 0, "id": "row-001", "task_id": "123e4567-e89b-12d3-a456-426614174000"}, {"index": 1, "id": "row-002", "task_id": "223e4567-e89b-12d3-a456-426614174000"} ], "failed_items": [] } ``` Poll the bulk job until `status` is `succeeded`, `failed`, or `partial`. ```bash theme={null} curl -X GET https://text.external-api.pangram.com/bulk/blk_123 \ -H "x-api-key: $PANGRAM_API_KEY" ``` Then page through results. ```bash theme={null} curl -X GET "https://text.external-api.pangram.com/bulk/blk_123/results?offset=0&limit=100" \ -H "x-api-key: $PANGRAM_API_KEY" ``` Send documents as multipart form data to create file-based AI detection results. ```bash theme={null} curl -s -X POST https://file-external.api.pangram.com \ -H "x-api-key: $PANGRAM_API_KEY" \ -F "files=@modeling/deployments/test/test_document.docx" \ -F "public_dashboard_link=true" \ | jq -r '.[0].public_dashboard_link' ``` Check text against a database of online content. Note the different base URL. ```bash theme={null} curl -X POST https://plagiarism.api.pangram.com \ -H "Content-Type: application/json" \ -H "x-api-key: $PANGRAM_API_KEY" \ -d '{ "text": "Text to check for plagiarism" }' ``` **Example Response** ```json theme={null} { "text": "Text to check for plagiarism", "plagiarism_detected": true, "plagiarized_content": [ { "source_url": "https://example.com/source", "matched_text": "Text to check for plagiarism", "similarity_score": 0.95 } ], "total_sentences": 1, "plagiarized_sentences": 1, "percent_plagiarized": 100.0 } ``` The text and bulk APIs temporarily accept an omitted `model` for backward compatibility and resolve it to `"default"`. New integrations should always send a selector returned by `GET /models`. A bulk selector applies to every item in the job. ## Error Handling | Status Code | Description | | --------------------------- | --------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | The request body is not properly formatted. | | `401 Unauthorized` | The `x-api-key` is missing or invalid. | | `402 Payment Required` | The account has insufficient credits. | | `403 Forbidden` | The requested model is not enabled for the API key, or the API key does not own the requested task or bulk job. | | `404 Not Found` | The requested task or bulk job does not exist. | | `413 Payload Too Large` | The bulk request exceeds the maximum billable units. | | `422 Unprocessable Entity` | The input text or model selector is invalid. | | `429 Too Many Requests` | The API key exceeds its configured rate limit. | | `500 Internal Server Error` | There was an error processing the request. | | `503 Service Unavailable` | The requested model is temporarily unavailable. | If you are running into errors, please reach out at [support@pangram.com](mailto:support@pangram.com). # Python SDK Source: https://docs.pangram.com/sdk/python Reference for the Pangram Python client library ## Installation ```bash theme={null} pip install pangram-sdk ``` ## Pangram The main client class for interacting with the Pangram Labs API. `PangramText` remains available for legacy imports, but `Pangram` is the recommended client name. ### Constructor ```python theme={null} from pangram import Pangram client = Pangram(api_key="your-api-key") ``` Your API key for Pangram Labs. If not provided, the `PANGRAM_API_KEY` environment variable will be used. Raises `ValueError` if the API key is not provided and not set in the environment. *** ### list\_models() List the detection models available to this API key. ```python theme={null} available_models = client.list_models() # e.g., ["default", "pangram-4"] ``` The returned `list[str]` preserves server order and reflects both the account's entitlements and current model availability. Do not hard-code the catalog or assume every API key sees the same values. Use one returned selector as the keyword-only `model` argument on text and bulk requests. The `model` argument is temporarily optional for backward compatibility. Omitting it preserves the existing wire payload, selects Pangram's server default, and emits a `DeprecationWarning`. Pass `model="default"` or another value from `list_models()` in new code. The SDK will require explicit model selection after September 30, 2026. *** ### predict() Classify text as AI-generated, AI-assisted, or human-written. `predict()` submits an async inference task, polls until the task completes, and returns the completed task payload. ```python theme={null} result = client.predict( text, public_dashboard_link=False, timeout=300, poll_interval=0.5, model="pangram-4", ) ``` **Parameters** The text to be classified. Keyword-only model selector returned by `list_models()`. Pass `"default"` to follow Pangram's current default model. Whether to include a public dashboard link in the completed response. Maximum number of seconds to wait for the async task to complete. Number of seconds to wait between polling attempts. Values below `0.1` are clamped to `0.1`. **Returns** A dictionary with the following fields after the task reaches `STAGE_SUCCESS`: Terminal async task stage. Successful responses return `"STAGE_SUCCESS"`. The analyzed text returned by the model. Pangram 4 may normalize the submitted text before inference; window offsets refer to this value. The API version identifier (e.g., `"4.0"` for Pangram 4). Classification headline summarizing the result. Long-form prediction string describing the classification. Short-form prediction string. Pangram 4 returns `"AI"`, `"Human"`, or `"Mixed"`. Fraction of text classified as AI-written (0.0–1.0). Fraction of text classified as AI-assisted (0.0–1.0). Fraction of text classified as human-written (0.0–1.0). Number of text segments classified as AI. Number of text segments classified as AI-assisted. Number of text segments classified as human. Dashboard link. Only present when `public_dashboard_link` is `True`. List of text windows and their classifications. Each window contains: The window text. Classification label. Pangram 4 returns `"AI-Generated"`, `"AI-Assisted"`, or `"Human Written"`. AI assistance score (0.0–1.0), where 0 means no AI assistance and 1.0 means AI-generated. Confidence level (`"High"`, `"Medium"`, `"Low"`). Starting character index in the returned top-level `text`. End-exclusive character index in the returned top-level `text`. Number of words in the window. Token length of the window. Whether Pangram 4's humanizer head classified the window as humanized. Present on every Pangram 4 window. Pangram 4 humanizer-head score from 0.0–1.0. Present on every Pangram 4 window. Results remain normal dictionaries. Typed applications can import `PredictionResult` and `PredictionWindow` from `pangram`. Raises `ValueError` if the API returns an error, the task fails, or the response is invalid. Raises `TimeoutError` if the task does not complete before `timeout`. *** ### predict\_with\_dashboard\_link() Classify text and include a public dashboard link in the completed response. ```python theme={null} result = client.predict_with_dashboard_link( text, timeout=300, poll_interval=0.5, model="pangram-4", ) ``` This is equivalent to: ```python theme={null} result = client.predict( text, public_dashboard_link=True, timeout=300, poll_interval=0.5, model="pangram-4", ) ``` The `timeout`, `poll_interval`, and keyword-only `model` parameters have the same behavior as `predict()`. *** ### submit\_bulk() Submit a Bulk API job for asynchronous AI detection across many inputs. Provide exactly one of `text` or `items`. Bulk jobs are processed asynchronously. Completion time depends on the number and length of submitted items and current system load. Use `get_bulk_status()` or `wait_for_bulk()` to monitor progress. Use `text=[...]` for plain string inputs, or `items=[{"id": "...", "text": "..."}]` when you want customer IDs returned with status and results. Do not pass both. ```python theme={null} bulk = client.submit_bulk( items=[ {"id": "row-001", "text": "First text to analyze"}, {"id": "row-002", "text": "Second text to analyze"}, ], model="pangram-4", ) bulk_id = bulk["bulk_id"] ``` **Parameters** List of input texts. Use this shape when you do not need customer item IDs. List of item dictionaries. Each item must include `text` and may include a unique customer-defined `id`. Keyword-only model selector returned by `list_models()`. Applies to the entire bulk job; per-item model selectors are not supported. **Returns** The ID of the bulk job. Initial status. Usually `queued`; returns `failed` if every item failed immediate validation. Total number of submitted items. Items accepted for processing. Each item includes `index`, optional `id`, and `task_id`. Items that failed immediate validation. Each item includes `index`, optional `id`, `task_id: None`, `stage`, and `error`. *** ### wait\_for\_bulk() Poll a bulk job until it reaches a terminal status. ```python theme={null} status = client.wait_for_bulk( bulk_id, timeout=3600, poll_interval=0.5, ) ``` Terminal statuses are `succeeded`, `failed`, and `partial`. Completion time depends on the number and length of submitted items and current system load. **Parameters** The bulk job ID returned by `submit_bulk()`. Maximum number of seconds to wait for terminal completion. Number of seconds to wait between polling attempts. Values below `0.1` are clamped to `0.1`. **Returns** The same dictionary returned by `get_bulk_status()` after the job reaches a terminal status. Raises `TimeoutError` if the job does not complete before `timeout`. *** ### get\_bulk\_status() Fetch the current status and counters for a bulk job. ```python theme={null} status = client.get_bulk_status(bulk_id) ``` **Returns** The ID of the bulk job. One of `queued`, `running`, `succeeded`, `failed`, or `partial`. Total number of submitted items. Number of items accepted for processing. Number of items that completed successfully. Number of items that failed. Job creation timestamp as Unix epoch seconds encoded as a string. Job completion timestamp as Unix epoch seconds encoded as a string. `None` while the job is not terminal. *** ### get\_bulk\_items() Fetch paginated item metadata for a bulk job. ```python theme={null} items = client.get_bulk_items(bulk_id, offset=0, limit=100) ``` **Parameters** The bulk job ID returned by `submit_bulk()`. Zero-based item offset. Maximum number of items to return. The API allows up to `1000`. **Returns** A dictionary containing `bulk_id`, `offset`, `limit`, `total_items`, and `items`. Each item includes `index`, optional `id`, `task_id`, `stage`, and optional `error`. *** ### get\_bulk\_results() Fetch all available results for a bulk job. ```python theme={null} results = client.get_bulk_results(bulk_id) for item in results["items"]: if item["result"] is not None: print(item["id"], item["result"]["prediction_short"]) for failed in results["failed_items"]: print(failed["id"], failed["error"]) ``` **Parameters** The bulk job ID returned by `submit_bulk()`. Number of submitted item slots to request per API call. The API allows up to `1000`. **Returns** A dictionary containing `bulk_id`, `total_items`, `items`, and `failed_items` aggregated across every results page. Successful completed items include `result` with the same shape returned by `predict()`. In-progress items have `result` set to `None`. `get_bulk_results()` materializes all pages into memory. For large jobs, use `get_bulk_results_page()` in a loop and process each page as it arrives. The SDK returns this dictionary as `BulkResults`; successful item results use `PredictionResult`. *** ### get\_bulk\_results\_page() Fetch one paginated results page for a bulk job. ```python theme={null} page = client.get_bulk_results_page(bulk_id, offset=0, limit=100) ``` Use this when you need incremental page-level inspection before fetching or storing the full result set. ```python theme={null} offset = 0 limit = 1000 while True: page = client.get_bulk_results_page(bulk_id, offset=offset, limit=limit) for item in page["items"]: process(item) for failed in page["failed_items"]: handle_failure(failed) offset += limit if offset >= page["total_items"]: break ``` **Parameters** The bulk job ID returned by `submit_bulk()`. Zero-based submitted-item offset. Maximum number of submitted item slots to return. The API allows up to `1000`. **Returns** A dictionary containing `bulk_id`, `offset`, `limit`, `total_items`, `items`, and `failed_items` for the requested page. The SDK returns this dictionary as `BulkResultsPage`. *** ### check\_plagiarism() Check text for potential plagiarism against a database of online content. ```python theme={null} result = client.check_plagiarism(text) ``` **Parameters** The text to check for plagiarism. **Returns** A dictionary with the following fields: The input text. Whether plagiarism was detected. List of detected plagiarized content with source URLs. Total number of sentences checked. List of sentences detected as plagiarized. Percentage of text detected as plagiarized. Raises `ValueError` if the API returns an error. *** ## Typed response contracts The SDK ships a `py.typed` marker and exports its public `TypedDict` contracts from `pangram`: ```python theme={null} from pangram import ( BulkResultItem, BulkResultMetadata, BulkResults, BulkResultsPage, PredictionResult, PredictionWindow, ) ``` | Type | Represents | | -------------------- | --------------------------------------------------------------------- | | `PredictionWindow` | One classified window, including optional Pangram 4 humanizer fields. | | `PredictionResult` | A successful text prediction. | | `BulkResultMetadata` | Status metadata shared by successful and failed bulk items. | | `BulkResultItem` | Bulk item metadata plus its prediction when processing succeeds. | | `BulkResultsPage` | One paginated bulk results response. | | `BulkResults` | All bulk results pages aggregated by the SDK. | The runtime values remain ordinary dictionaries and lists; these types provide static checking without changing existing access patterns. *** ## Deprecated Methods The following SDK compatibility methods are deprecated and may be removed on August 1, 2026. Use `predict()` for one-off calls or `submit_bulk()` for asynchronous bulk jobs. ### predict\_short() Deprecated Forwards to `predict()` and returns the current async result schema. ```python theme={null} result = client.predict_short(text, model="pangram-4") ``` ### batch\_predict() Deprecated Calls `predict()` once per input text. Use `submit_bulk()` for asynchronous bulk jobs. ```python theme={null} results = client.batch_predict( ["text one", "text two"], model="pangram-4", ) ``` ## Removed Legacy Methods `predict_extended()` and `predict_sliding_window()` are no longer part of the current `pangram-sdk`. Use `predict()` for current AI detection and segment-level results.