Skip to content

Latest commit

 

History

History
877 lines (677 loc) · 31.7 KB

File metadata and controls

877 lines (677 loc) · 31.7 KB

GET /api/v1/result/{id}

Retrieve a previously completed PDF analysis by its unique check ID.

Endpoint

GET https://api.htpbe.tech/v1/result/{id}

Authentication

This endpoint requires API key authentication via the Authorization header.

Authorization: Bearer YOUR_API_KEY

Data Isolation

Important: You can only retrieve analysis results that belong to your API client. Attempting to access another client's results will return a 404 error, even if the check ID exists. This ensures complete data privacy and isolation between API clients.


Request

Path Parameters

Parameter Type Required Description
id string Yes Check ID returned from POST /api/v1/analyze. UUID v4 for all requests — live and test keys both return UUID v4 IDs.

id Parameter Details

Live key format: UUID v4 — xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx

Test key format: Deterministic UUID v4 — fixed all-zeros pattern, e.g. 00000000-0000-4000-8000-000000000001

Valid Examples:

  • 506a6b1b-1360-48a2-b389-abb346f85d04 (live key request)
  • 00000000-0000-4000-8000-000000000001 (test key request — clean.pdf)

Invalid Examples:

  • abc123 (too short, not a UUID)
  • `` (empty string)

Where to Get: The id field returned by POST /api/v1/analyze.

Headers

Header Type Required Description
Authorization string Yes Bearer token with your API key (Bearer htpbe_live_... or Bearer htpbe_test_...). The Bearer prefix is recommended but optional — sending the raw key directly is also accepted, but only if the key starts with htpbe_ (e.g., Authorization: htpbe_live_sk_...).

Example Request

curl https://api.htpbe.tech/v1/result/506a6b1b-1360-48a2-b389-abb346f85d04 \
  -H "Authorization: Bearer htpbe_live_sk_1234567890abcdef"
// Node.js / TypeScript
const checkId = '506a6b1b-1360-48a2-b389-abb346f85d04';

const response = await fetch(`https://api.htpbe.tech/v1/result/${checkId}`, {
  headers: {
    Authorization: `Bearer ${process.env.HTPBE_API_KEY}`,
  },
});

const result = await response.json();
# Python
import requests
import os

check_id = '506a6b1b-1360-48a2-b389-abb346f85d04'

response = requests.get(
    f'https://api.htpbe.tech/v1/result/{check_id}',
    headers={
        'Authorization': f"Bearer {os.getenv('HTPBE_API_KEY')}"
    }
)

result = response.json()

Response

Success Response (200 OK)

Returns a ResultResponse object containing all stored analysis data for the check.

Note: /api/v1/analyze returns only { "id": "..." }. This endpoint is where all analysis data lives: metadata, structure, signatures, findings, and verdict details.

Response Structure

{
  // Core Identification
  id: string;
  filename: string;
  check_date: number | null;
  file_size: number;

  // Algorithm version tracking
  algorithm_version: string;
  current_algorithm_version: string;
  outdated_warning?: string;

  // Primary Verdict
  status: "intact" | "modified" | "inconclusive";
  status_reason?: "consumer_software_origin" | "online_editor_origin" | "scanned_document" | "unverifiable_metadata" | "filled_form_origin" | "fill_sign_origin";

  // PDF Metadata (Unix timestamps)
  creation_date: number | null;
  modification_date: number | null;
  creator: string | null;
  producer: string | null;

  // Critical Modification Detection
  modification_confidence: string | null;

  // Metadata Analysis
  date_sequence_valid: boolean;
  metadata_completeness_score: number;

  // PDF Structure
  xref_count: number;
  has_incremental_updates: boolean;
  update_chain_length: number;
  pdf_version: string | null;

  // Digital Signatures
  has_digital_signature: boolean;
  signature_count: number;
  signature_removed: boolean;
  modifications_after_signature: boolean;

  // Content Analysis
  page_count: number;
  object_count: number;
  has_javascript: boolean;
  has_embedded_files: boolean;

  // Modification Evidence
  modification_markers: string[];

  // Responsible-use guardrail (always present)
  usage_caution: {
    safe_for_automated_adverse_decision: false;
    recommended_action: "route_to_human_review" | "request_from_issuer" | "no_action";
    message: string;
  };
}

Response Fields

Core Identification Fields

id
  • Type: string (UUID v4)
  • Always Present: Yes
  • Description: Unique identifier for this check
  • Format: xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx
  • Example: "506a6b1b-1360-48a2-b389-abb346f85d04"
filename
  • Type: string
  • Always Present: Yes
  • Description: The stored filename for this check. If original_filename was provided in the POST /analyze request body, that value is used. Otherwise it is extracted from the last segment of the url path.
  • Examples:
    • "contract.pdf" (provided as original_filename in the analyze request, or extracted from https://example.com/docs/contract.pdf)
    • "invoice-2024-01.pdf"
    • "document.pdf" (default set at analysis time when no filename is determinable from the URL)
    • "" (empty string for legacy records created before filename tracking)
check_date
  • Type: number | null (Unix timestamp in seconds)
  • Can Be Null: Yes — null for test key results (synthetic responses have no real analysis timestamp) and for legacy records created before timestamp tracking was introduced
  • Description: Timestamp when the analysis was performed
  • Format: Seconds since Unix epoch (January 1, 1970 00:00:00 UTC)
  • Example: 1736542583 = January 10, 2025, 18:23:03 UTC
  • Convert to Date:
    • JavaScript: check_date ? new Date(check_date * 1000) : null
    • Python: datetime.fromtimestamp(check_date) if check_date else None
file_size
  • Type: number (integer, bytes)
  • Always Present: Yes
  • Range: 1 to 10485760 (10 MB)
  • Description: File size in bytes
  • Example: 245632 = ~240 KB
  • Convert to MB: file_size / 1024 / 1024

Algorithm Version Fields

Note: Version numbers reflect the algorithm in use at the time of analysis. The current version may differ.

algorithm_version
  • Type: string
  • Always Present: Yes
  • Description: Version of the detection algorithm used when this check was performed. Defaults to "1.0.0" for records created before algorithm versioning was introduced.
  • Format: Semantic versioning (e.g., "2.2.1")
  • Usage: Compare against the current version to determine if re-analysis is recommended
  • Example: "2.2.1"
current_algorithm_version
  • Type: string
  • Always Present: Yes
  • Description: The current algorithm version running on the server
  • Format: Semantic versioning (e.g., "2.2.1")
  • Usage: Compare algorithm_version against current_algorithm_version to determine if the check is outdated. If algorithm_version !== current_algorithm_version, the check was performed with an older algorithm and re-analysis is recommended.
  • Example: "2.2.1"
outdated_warning
  • Type: string (optional)
  • Present When: algorithm_version is older than current_algorithm_version (semver comparison — a future version would not trigger this warning even if the values differ)
  • Absent When: algorithm_version is current
  • Description: Human-readable explanation of what changed in the newer algorithm version and why re-analysis is recommended
  • Example: "Our detection software has been updated since this file was analyzed. The results shown below may no longer be accurate. We recommend re-analyzing this file for more accurate results."

Analysis Results Fields

status
  • Type: "intact" | "modified" | "inconclusive"
  • Always Present: Yes
  • Description: PRIMARY VERDICT. Priority: modified > inconclusive > intact
    • "modified" — forensic evidence of post-creation modification detected; takes priority over origin type — a modified Word or Excel document is still modified
    • "inconclusive" — consumer software, online editor, scanned, unverifiable (re-rendered or image-only), filled-form, or Fill & Sign origin with no modification detected; integrity check does not apply to documents anyone can create, reprocess, fill in, or scan from scratch. The specific cause is in status_reason
    • "intact" — no structural evidence of modification, and the document did not originate from consumer software, an online editor, or a scan
  • Note: status_reason only appears when status === "inconclusive"
status_reason
  • Type: "consumer_software_origin" | "online_editor_origin" | "scanned_document" | "unverifiable_metadata" | "filled_form_origin" | "fill_sign_origin" | absent
  • Always Present: No — only present when status === "inconclusive"
  • Description: Explains why the result is inconclusive.
  • Values:
    • "consumer_software_origin" — the PDF was created by consumer software (Microsoft Word, LibreOffice, Google Docs, etc.) or a freely available HTML-to-PDF renderer. These tools let anyone create a document from scratch, so there is no meaningful "original" to compare against. For a file that claims institutional origin (a payslip, an invoice, a bank statement), this origin is itself a strong signal to route for review — a real payroll or banking system does not distribute documents this way. If the document will support a financial or compliance decision, verify its content directly with the issuing organisation.
    • "online_editor_origin" — the PDF was processed through an online editing service (iLovePDF, Smallpdf, PDF24, etc.). These services strip original metadata, making provenance verification impossible.
    • "scanned_document" — the PDF is a pure raster scan (no fonts, no text layer, at least one image per page). Anyone can print and scan a document, so its content cannot be verified through metadata analysis.
    • "unverifiable_metadata" — the PDF was rebuilt by a render engine (e.g. a browser print backend) that flattens away the structural history an integrity check depends on. The original provenance can no longer be established.
    • "filled_form_origin" — the PDF is an interactive form (AcroForm) with at least one filled field. A form can be filled or re-filled any number of times, so a structural check cannot certify what it currently shows.
    • "fill_sign_origin" — the PDF carries an Adobe Fill & Sign overlay, which lets anyone add text and marks over a page. A structural check cannot separate an original fill from a later edit.
  • Usage: Always check status_reason when status === "inconclusive" — it tells you why the result is inconclusive, not just that it is.

Handle every branch — an inconclusive verdict is not a failure and not a pass. It means the integrity check does not apply, so route the document by why rather than treating it as clean:

function handleResult(result) {
  switch (result.status) {
    case 'modified':
      // Forensic evidence of post-creation modification — route to human review.
      return 'review';

    case 'intact':
      // No structural evidence of modification.
      return 'accept';

    case 'inconclusive':
      // Integrity check does not apply. Branch on status_reason to decide handling.
      switch (result.status_reason) {
        case 'scanned_document':
        // Pure raster scan — no text layer, provenance unverifiable.
        case 'online_editor_origin':
        // Processed through an online editor — original metadata stripped.
        case 'unverifiable_metadata':
        // Re-rendered or image-only — structural history flattened away.
        case 'filled_form_origin':
        // Interactive form with filled fields — content can be re-filled at any time.
        case 'fill_sign_origin':
        // Adobe Fill & Sign overlay — an original fill can't be told from a later edit.
        case 'consumer_software_origin':
          // Created in consumer software or a free HTML-to-PDF renderer.
          // On a document that CLAIMS institutional origin (payslip, invoice, bank
          // statement), this is itself a red flag — verify the content directly with
          // the issuing organisation before relying on it.
          return 'verify-with-issuer';
        default:
          return 'verify-with-issuer';
      }
  }
}

PDF Metadata Fields (Unix Timestamps)

All timestamps are Unix integers (seconds since epoch). Convert with: new Date(timestamp * 1000) in JavaScript, datetime.fromtimestamp(ts) in Python.

creation_date
  • Type: number | null (Unix timestamp in seconds)
  • Can Be Null: Yes
  • Description: PDF creation timestamp from embedded metadata
  • Null When: PDF does not contain creation date
  • Example: 1704110400 = January 2, 2024 00:00:00 UTC
  • Convert: JavaScript: new Date(creation_date * 1000).toISOString()
modification_date
  • Type: number | null (Unix timestamp in seconds)
  • Can Be Null: Yes
  • Description: Last modification timestamp from embedded metadata
  • Null When: PDF does not contain modification date
  • Critical: If different from creation_date, indicates modification
  • Example: 1707840000 = February 13, 2024 12:00:00 UTC
creator
  • Type: string | null
  • Can Be Null: Yes
  • Description: Application that created the original document
  • Example: "Microsoft Word for Microsoft 365"
  • Common Values: "Microsoft Word for Microsoft 365", "Adobe InDesign CC", "LibreOffice Writer", "Google Docs"
producer
  • Type: string | null
  • Can Be Null: Yes
  • Description: Software that generated the final PDF
  • Example: "Adobe PDF Library 15.0"
  • Common Values: "Adobe PDF Library 15.0", "PDFKit", "Microsoft: Print To PDF", "iText 7.0.0"

Critical Modification Detection Fields

modification_confidence
  • Type: string | null (enum)
  • Can Be Null: Yes
  • Description: How certain the algorithm is about the modification verdict. Use it to decide how to route the case for review — never as a trigger for an automatic adverse decision against a person (see usage_caution).
  • Possible Values:
    • "certain" — conclusive structural or cryptographic evidence; the finding cannot be a false positive (date mismatch, post-signature modification, signature removal). Treat the document as modified and route it to human review or request a fresh copy directly from the issuer — do not auto-reject the person on this alone.
    • "high" — strong forensic evidence; flag for manual review — highly reliable but rare false positives are possible in unusual legitimate workflows (e.g. linearization, batch processing pipelines)
    • "none" — no modification detected; the document can proceed, subject to your own downstream checks
  • Relationship to status: certain and high always correspond to status: "modified". none corresponds to status: "intact" or "inconclusive" depending on origin.
  • Null When: Legacy records before this field was added

Metadata Analysis Fields

date_sequence_valid
  • Type: boolean
  • Always Present: Yes
  • Description: Whether creation and modification dates are in chronologically valid sequence
  • Valid Sequence: creation_datemodification_date
  • Possible Values:
    • true - Dates are valid (creation before or equal to modification)
    • false - Suspicious - Modification date is before creation date (impossible in normal workflow)
  • Red Flag: false strongly suggests date tampering
metadata_completeness_score
  • Type: number (integer)
  • Always Present: Yes
  • Range: 0 to 100
  • Description: How complete the PDF metadata is (percentage of fields present)
  • Calculation: Based on presence of:
    • Creation date
    • Modification date
    • Creator
    • Producer
    • Title, Subject, Author (standard metadata)
  • Interpretation:
    • 90-100 - Excellent metadata, most fields present
    • 70-89 - Good metadata coverage
    • 50-69 - Moderate metadata
    • 30-49 - Limited metadata
    • 0-29 - Very sparse metadata (may hinder analysis)
  • Impact: Higher scores enable more confident modification detection

PDF Structure Fields

xref_count
  • Type: number (integer)
  • Always Present: Yes
  • Description: Number of cross-reference (xref) tables in the PDF
  • Interpretation: 1 = original document, 2+ = document has been modified and saved multiple times
has_incremental_updates
  • Type: boolean
  • Always Present: Yes
  • Description: Whether PDF has incremental update sections (been saved multiple times after initial creation)
  • Values: true = PDF has been edited and saved incrementally, false = PDF was generated in one operation
update_chain_length
  • Type: number (integer)
  • Always Present: Yes
  • Description: Number of update sections in PDF structure (how many times the PDF was saved)
  • Interpretation: 1 = original, 2-5 = light editing, 6-10 = moderate editing, 11+ = heavy editing
pdf_version
  • Type: string | null
  • Can Be Null: Yes
  • Description: PDF specification version
  • Examples: "1.7", "1.4", "2.0", null
  • Common Versions: "1.7" (most common, Acrobat 8.x+), "1.4" (Acrobat 5.x), "2.0" (modern ISO standard)

Digital Signatures Fields

has_digital_signature
  • Type: boolean
  • Always Present: Yes
  • Description: Whether PDF currently contains digital signatures
  • Values: true = digitally signed, false = not signed
  • Note: Signature validity is NOT checked (only presence)
signature_count
  • Type: number (integer)
  • Always Present: Yes
  • Description: Number of digital signature fields in the PDF
  • Range: 0 and higher
signature_removed
  • Type: boolean
  • Always Present: Yes
  • Description: Whether a digital signature was removed from the document
  • Critical: If true, this is strong evidence of tampering
modifications_after_signature
  • Type: boolean
  • Always Present: Yes
  • Description: Whether PDF was modified after being digitally signed
  • Critical: If true, the digital signature is likely invalidated

Content Analysis Fields

page_count
  • Type: number (integer)
  • Always Present: Yes
  • Range: 1 and higher
  • Description: Total number of pages in the PDF document
  • Example: 12 = 12-page document
  • Usage: Useful for estimating document size and complexity
object_count
  • Type: number (integer)
  • Always Present: Yes
  • Range: 0 and higher
  • Description: Number of PDF objects in the internal structure
  • What It Means:
    • PDF objects include: pages, fonts, images, annotations, forms, etc.
    • Higher object count generally means more complex document
    • Useful for detecting unusual structural complexity
  • Typical Ranges:
    • 50-200 - Simple text document
    • 200-500 - Document with images
    • 500-1000 - Complex document with forms/annotations
    • 1000+ - Very complex document or potential obfuscation
has_javascript
  • Type: boolean
  • Always Present: Yes
  • Description: Whether PDF contains embedded JavaScript code
  • Values: true = JavaScript present (potential security risk), false = no JavaScript detected
  • Security Note: JavaScript in PDFs can be used for malicious purposes
has_embedded_files
  • Type: boolean
  • Always Present: Yes
  • Description: Whether PDF has embedded file attachments
  • Values: true = has attachments (potential security risk), false = no attachments
  • Security Note: Attachments can hide malware

Modification Evidence Fields

modification_markers
  • Type: string[] (array of strings)
  • Always Present: Yes
  • Description: All modification signals detected, ordered strongest-first. The first element (modification_markers[0]) is the strongest marker — the single most important forensic indicator that drove the verdict. Usually contains one entry; may have two or three when multiple independent signals fired simultaneously (e.g. dates disagree AND an editing tool detected). Empty when status is "intact" or "inconclusive".
  • Format: Each entry is a stable machine-readable id (e.g. HTPBE_SIGNATURE_REMOVED, HTPBE_DATES_DISAGREE). The full id → outcome-label dictionary is published on htpbe.tech/how — branch on the id in your integration, render the user-facing label from the dictionary.
  • Empty When: No modification detected (status: "intact" or status: "inconclusive")
  • Example Values:
    • "HTPBE_DATES_DISAGREE"
    • "HTPBE_MULTIPLE_REVISION_LAYERS"
    • "HTPBE_SIGNATURE_REMOVED"
    • "HTPBE_POST_SIGNATURE_EDIT"
    • "HTPBE_EDITING_TOOL_FINGERPRINT"
    • "HTPBE_IDENTITY_BLANKED"
    • "HTPBE_FONT_VS_TOOL_MISMATCH"
    • "HTPBE_DESIGN_TEMPLATE_ASSEMBLY"
    • "HTPBE_TEXT_OVERLAY_ON_SCAN"
    • "HTPBE_PAGES_FROM_MULTIPLE_SOURCES"

Responsible-Use Field

usage_caution
  • Type: object
  • Always Present: Yes
  • Description: In-contract responsible-use guardrail. A structural verdict describes the file, not the person who sent it, so it must never be the sole basis for an automatic adverse decision (rejecting or denying an applicant, claimant, or customer). This field ships the guardrail in the payload itself, not only in the docs — branch on recommended_action to route the case instead of auto-rejecting.
  • Fields:
    • safe_for_automated_adverse_decisionboolean, always false. A machine-checkable assertion that this verdict alone must not drive an automatic adverse decision against a person.
    • recommended_action"route_to_human_review" (for status: "modified"), "request_from_issuer" (for status: "inconclusive" — the check could not confirm integrity, which is not proof of fraud), or "no_action" (for status: "intact").
    • message — human-readable guidance matching recommended_action.
  • Example:
{
  "safe_for_automated_adverse_decision": false,
  "recommended_action": "route_to_human_review",
  "message": "Structural evidence of post-creation modification was found. Route this document to a human reviewer before any decision — do not use this verdict as the sole basis for an automatic adverse decision against a person."
}

Example Response

{
  "id": "506a6b1b-1360-48a2-b389-abb346f85d04",
  "filename": "contract.pdf",
  "check_date": 1736542583,
  "file_size": 245632,
  "algorithm_version": "2.2.1",
  "current_algorithm_version": "2.2.1",
  "status": "modified",
  "creation_date": 1704110400,
  "modification_date": 1707840000,
  "creator": "Adobe Acrobat Pro DC",
  "producer": "Adobe PDF Library 15.0",
  "modification_confidence": "certain",
  "date_sequence_valid": true,
  "metadata_completeness_score": 90,
  "xref_count": 2,
  "has_incremental_updates": true,
  "update_chain_length": 3,
  "pdf_version": "1.7",
  "has_digital_signature": false,
  "signature_count": 0,
  "signature_removed": true,
  "modifications_after_signature": false,
  "page_count": 12,
  "object_count": 487,
  "has_javascript": false,
  "has_embedded_files": false,
  "modification_markers": ["HTPBE_SIGNATURE_REMOVED", "HTPBE_DATES_DISAGREE"],
  "usage_caution": {
    "safe_for_automated_adverse_decision": false,
    "recommended_action": "route_to_human_review",
    "message": "Structural evidence of post-creation modification was found. Route this document to a human reviewer before any decision — do not use this verdict as the sole basis for an automatic adverse decision against a person."
  }
}

Example Response — Inconclusive (Consumer Software Origin)

{
  "id": "00000000-0000-4000-8000-000000000011",
  "filename": "inconclusive.pdf",
  "check_date": null,
  "file_size": 204800,
  "algorithm_version": "2.2.1",
  "current_algorithm_version": "2.2.1",
  "status": "inconclusive",
  "status_reason": "consumer_software_origin",
  "creation_date": 1709283600,
  "modification_date": 1709283600,
  "creator": "Microsoft Excel 2019",
  "producer": "Microsoft: Print To PDF",
  "modification_confidence": "none",
  "date_sequence_valid": true,
  "metadata_completeness_score": 65,
  "xref_count": 1,
  "has_incremental_updates": false,
  "update_chain_length": 1,
  "pdf_version": "1.7",
  "has_digital_signature": false,
  "signature_count": 0,
  "signature_removed": false,
  "modifications_after_signature": false,
  "page_count": 1,
  "object_count": 82,
  "has_javascript": false,
  "has_embedded_files": false,
  "modification_markers": [],
  "usage_caution": {
    "safe_for_automated_adverse_decision": false,
    "recommended_action": "request_from_issuer",
    "message": "The check could not confirm this document’s integrity, which is not proof of fraud. Confirm the content directly with the issuing organisation or route it to human review — do not treat inconclusive as an automatic rejection."
  }
}

Example Response — Inconclusive (Online Editor Origin)

{
  "id": "00000000-0000-4000-8000-000000000014",
  "filename": "inconclusive-online-editor.pdf",
  "check_date": null,
  "file_size": 312000,
  "algorithm_version": "2.2.1",
  "current_algorithm_version": "2.2.1",
  "status": "inconclusive",
  "status_reason": "online_editor_origin",
  "creation_date": null,
  "modification_date": null,
  "creator": null,
  "producer": "iLovePDF",
  "modification_confidence": "none",
  "date_sequence_valid": true,
  "metadata_completeness_score": 15,
  "xref_count": 1,
  "has_incremental_updates": false,
  "update_chain_length": 1,
  "pdf_version": "1.7",
  "has_digital_signature": false,
  "signature_count": 0,
  "signature_removed": false,
  "modifications_after_signature": false,
  "page_count": 2,
  "object_count": 110,
  "has_javascript": false,
  "has_embedded_files": false,
  "modification_markers": [],
  "usage_caution": {
    "safe_for_automated_adverse_decision": false,
    "recommended_action": "request_from_issuer",
    "message": "The check could not confirm this document’s integrity, which is not proof of fraud. Confirm the content directly with the issuing organisation or route it to human review — do not treat inconclusive as an automatic rejection."
  }
}

Example Response — Inconclusive (Scanned Document)

{
  "id": "00000000-0000-4000-8000-000000000015",
  "filename": "scanned-document.pdf",
  "check_date": null,
  "file_size": 890000,
  "algorithm_version": "2.2.1",
  "current_algorithm_version": "2.2.1",
  "status": "inconclusive",
  "status_reason": "scanned_document",
  "creation_date": null,
  "modification_date": null,
  "creator": null,
  "producer": null,
  "modification_confidence": "none",
  "date_sequence_valid": true,
  "metadata_completeness_score": 0,
  "xref_count": 1,
  "has_incremental_updates": false,
  "update_chain_length": 1,
  "pdf_version": "1.4",
  "has_digital_signature": false,
  "signature_count": 0,
  "signature_removed": false,
  "modifications_after_signature": false,
  "page_count": 3,
  "object_count": 45,
  "has_javascript": false,
  "has_embedded_files": false,
  "modification_markers": [],
  "usage_caution": {
    "safe_for_automated_adverse_decision": false,
    "recommended_action": "request_from_issuer",
    "message": "The check could not confirm this document’s integrity, which is not proof of fraud. Confirm the content directly with the issuing organisation or route it to human review — do not treat inconclusive as an automatic rejection."
  }
}

Error Responses

All errors follow this format:

{
  "error": "Human-readable error message",
  "code": "machine_readable_error_code",
  "details": "Optional additional context (present for some errors)"
}

400 Bad Request

Returned when the check ID format is invalid.

{
  "error": "Invalid check ID format",
  "code": "invalid_request"
}

Causes:

  • id is empty string
  • id is not a valid UUID v4 (e.g. abc123, 12345678-1234-1234-1234-12345678)
  • id contains invalid characters

Solution: Ensure you're using the full UUID v4 returned by POST /api/v1/analyze or from the id field in GET /api/v1/checks. Format: xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx (32 hex digits with 4 hyphens).


401 Unauthorized

Authentication errors (same as analyze endpoint).

See: analyze.md for details.


402 Payment Required

No active subscription found for this API key.

See: analyze.md for details.


403 Forbidden

Access forbidden due to account status (deactivated key).

See: analyze.md for details.


404 Not Found

Check not found or access denied.

{
  "error": "Check not found or access denied",
  "code": "not_found"
}

Causes:

  1. Check ID doesn't exist in the database
  2. Check ID belongs to another API client (data isolation)
  3. Check ID is malformed but passed basic validation

Security Note: For privacy, we intentionally don't distinguish between "doesn't exist" and "belongs to another client". This prevents enumeration attacks.

Solution:

  • Verify the check ID is correct
  • Ensure you're using the API key that created the check
  • If you need to share results between API clients, contact support for guidance

500 Internal Server Error

Server error during retrieval.

{
  "error": "Failed to fetch result",
  "code": "internal_error"
}

Cause: Unexpected database or server error.

Solution:

  • Retry the request
  • If persists, contact support with the check ID

Use Cases

1. Building Audit Trails

Store check IDs and retrieve full results later for compliance:

// Store check ID after analysis
await db.documents.create({
  id: uploadId,
  htpbe_check_id: analysisResponse.id,
  verified_at: new Date(),
});

// Later, retrieve full details for audit
const auditData = await fetch(`https://api.htpbe.tech/v1/result/${doc.htpbe_check_id}`, {
  headers: { Authorization: `Bearer ${apiKey}` },
});

2. Detailed Reporting

Use the additional fields for comprehensive reports:

const result = await getResult(checkId);

const report = {
  summary:
    result.status === 'modified'
      ? 'Modified'
      : result.status === 'inconclusive'
        ? 'Unverifiable'
        : 'Original',

  // Use fields not available in analyze endpoint
  details: {
    pages: result.page_count,
    objects: result.object_count,
    metadataQuality: result.metadata_completeness_score,
    analysisDate: new Date(result.check_date * 1000),
  },

  criticalMarkers: result.modification_markers,
};

Related Endpoints: