Working with review results | 1099Policy

Working with review results

Once a certificate is processed, you can retrieve detailed results to understand what passed, what failed, and why. This guide covers how to fetch results and handle each status type in your application.

Fetching results

Results are available once processing completes (status is no longer pending or processing). Use the expand parameter to control the level of detail returned.

Without expansion – Basic status only

curl https://api.1099policy.com/api/v1/files/certificates/cert_aBcDeFgHiJ \
  -u YOUR_SECRET_KEY:
{
  "id": "cert_aBcDeFgHiJ",
  "contractor": "cn_abc123",
  "status": "flagged",
  "created": 1706745600,
  "updated": 1706745620,
  "filename": "acme-corp-coi-2024.pdf",
  "pdf_url": "https://...",
  "review_results": null
}

Abbreviated results – Summary counts

curl "https://api.1099policy.com/api/v1/files/certificates/cert_aBcDeFgHiJ?expand[]=review_results" \
  -u YOUR_SECRET_KEY:
{
  "id": "cert_aBcDeFgHiJ",
  "contractor": "cn_abc123",
  "status": "flagged",
  "created": 1706745600,
  "updated": 1706745620,
  "filename": "acme-corp-coi-2024.pdf",
  "pdf_url": "https://...",
  "review_results": {
    "id": "ca_xYzAbCdEfG",
    "status": "flagged",
    "summary": {
      "total_rules": 5,
      "passed": 4,
      "failed": 1
    },
    "created": 1706745610
  }
}

Full results – Complete parsed data and audit details

curl "https://api.1099policy.com/api/v1/files/certificates/cert_aBcDeFgHiJ?expand[]=review_results.full" \
  -u YOUR_SECRET_KEY:
{
  "id": "cert_aBcDeFgHiJ",
  "contractor": "cn_abc123",
  "status": "flagged",
  "created": 1706745600,
  "updated": 1706745620,
  "filename": "acme-corp-coi-2024.pdf",
  "pdf_url": "https://...",
  "review_results": {
    "id": "ca_xYzAbCdEfG",
    "status": "flagged",
    "parsed_certificate_json": {
      "coverages": {
        "commercial_general_liability": {
          "policy_expiration_date": "03/15/2025",
          "policy_number_string": "CGL-2024-001",
          "limits": {
            "general_aggregate_dollars": 2000000,
            "each_occurrence_dollars": 1000000,
            "products_completed_operations_dollars": 1000000
          }
        },
        "workers_compensation": {
          "policy_expiration_date": "06/30/2024",
          "policy_number_string": "WC-789456"
        }
      },
      "insured": {
        "name": "Acme Corporation LLC"
      },
      "description_of_operations": {
        "signature": true,
        "additional_insured_names": ["Client Corp Inc."]
      }
    },
    "audit_results": [
      {
        "id": "car_aB1cD2eF3g",
        "rule_path": "coverages.commercial_general_liability.limits.general_aggregate_dollars",
        "rule_name": null,
        "result": "pass",
        "message": "Coverage for commercial general liability is sufficient. The limit for general aggregate is $2,000,000, which meets the required $1,000,000.",
        "manually_approved": false,
        "created": 1706745611
      },
      {
        "id": "car_oP7qR8sT9u",
        "rule_path": "coverages.workers_compensation.policy_expiration_date",
        "rule_name": null,
        "result": "fail",
        "message": "Coverage for workers compensation has expired 'policy expiration date'. Policy expired on 06/30/2024.",
        "manually_approved": false,
        "created": 1706745611
      },
      {
        "id": "car_vW0xY1zA2b",
        "rule_path": "description_of_operations.additional_insured_names",
        "rule_name": "Additional Insured Check",
        "result": "pass",
        "message": "Rule for additional insureds was checked",
        "manually_approved": false,
        "created": 1706745612
      }
    ],
    "created": 1706745610,
    "updated": 1706745615
  }
}

When to use each expansion level

Use case Expansion Why
Dashboard status indicator None Just need pass/fail status
Summary counts for reporting review_results Shows total/passed/failed without payload overhead
Displaying failure reasons to users review_results.full Need audit_results with messages
Debugging parsing issues review_results.full Need parsed_certificate_json to see extracted data

Understanding parsed_certificate_json

The parsed_certificate_json object contains everything the AI extracted from the PDF. Use this to:

Key sections:

Field Contains
insured The contractor/company named as insured
certificate_holder Your organization's info as listed on the certificate
coverages Coverage details organized by type
description_of_operations Free-text description field, including additional insured names and signature presence

Coverage structure example

{
  "coverages": {
    "commercial_general_liability": {
      "limits": {
        "each_occurrence_dollars": 1000000,
        "general_aggregate_dollars": 2000000,
        "products_completed_operations_dollars": 1000000
      },
      "policy_number_string": "CGL-2024-001",
      "policy_expiration_date": "03/15/2025"
    }
  }
}

Understanding audit_results

The audit_results array contains one entry for each rule evaluated:

Field Type Description
id string Unique identifier (prefixed with car_)
rule_path string or null The data path that was checked (e.g., coverages.commercial_general_liability.limits.each_occurrence_dollars)
rule_name string or null Human-readable rule name, when available
result string or null pass or fail
message string or null Explanation of the result
manually_approved boolean Whether a compliance reviewer manually approved a failed rule
created integer Unix timestamp of when the evaluation occurred

Null rule_name rule_name may be null for standard coverage limit rules. Use rule_path to identify which rule was evaluated, or display the message which always describes the result.

Example: Identifying failed rules

response = requests.get(
    f'https://api.1099policy.com/api/v1/files/certificates/{cert_id}?expand[]=review_results.full',
    auth=('YOUR_SECRET_KEY', '')
)
cert = response.json()

if cert['review_results']:
    failed_rules = [
        r for r in cert['review_results']['audit_results']
        if r['result'] == 'fail' and not r['manually_approved']
    ]

for rule in failed_rules:
        # Use message for display since rule_name may be null
        print(f"Failed: {rule['message']}")

Handling each status

Build your integration to handle all possible statuses:

def handle_certificate_result(certificate):
    status = certificate['status']

if status == 'approved':
        # All requirements met - contractor is cleared
        approve_contractor(certificate['contractor'])

elif status == 'flagged':
        # Some rules failed - needs review
        # Fetch full results to show what failed
        results = fetch_full_results(certificate['id'])
        queue_for_compliance_review(certificate, results)

elif status == 'denied':
        # Manually denied by compliance reviewer
        notify_contractor_denied(certificate['contractor'])

elif status == 'error':
        # Processing failed - see Edge Cases guide
        handle_processing_error(certificate)

elif status in ['pending', 'processing']:
        # Still processing - wait for webhook
        pass

Status-specific guidance

Status Recommended action
approved Proceed with contractor onboarding or activation
flagged Present failed rules to compliance team for manual review. They can approve individual rules or request a new certificate.
denied Notify contractor. They'll need to obtain different coverage and upload a new certificate.
error Typically a file issue. See Edge Cases & Troubleshooting for common causes and solutions.

Manually approved rules

When a compliance reviewer manually approves a failed rule, the manually_approved field is set to true. The rule still shows result: "fail" but is treated as passing for overall status calculation.

In your UI, you may want to distinguish these:

for rule in audit_results:
    if rule['result'] == 'pass':
        display_as_passed(rule)
    elif rule['manually_approved']: 
        display_as_manually_approved(rule)  # Show with different styling
    else:
        display_as_failed(rule)

Voided audit results

In rare cases, audit results may be voided (e.g., if evaluated against an incorrect requirement). Voided results are excluded from the API response entirely—they don't appear in audit_results and aren't counted in the summary totals. There's no need to handle them in your integration.

Missing review results

If review_results is null:

Scenario Explanation
Status is pending or processing Processing hasn't completed yet
Status is error Processing failed before results could be generated
Expansion parameter not included Add ?expand[]=review_results to your request

Always check status before attempting to access review_results.

Next: Set up webhooks to receive real-time notifications when processing completes.