Skip to main content
POST
Submit a standardized inbound notification

Submit Inbound Notification

Use this endpoint to submit verification responses from external parties. The system processes responses through various channels (email, forms, fax, and generic JSON) and automatically extracts verification details using AI.

Authentication

Bearer Token Required - Include your JWT token in the Authorization header.

Quick Examples

Request Parameters

Optional Fields

string
Unique identifier for this message. If not provided, the system will auto-generate one using the format msg_<timestamp>_<random>. You can also provide it in messageData.id - the system will use the top-level messageId if present, otherwise messageData.id, otherwise auto-generate.
string
Thread identifier to link related messages. If not provided, the system will use the messageId as the threadId. You can also provide it in messageData.threadId - the system will use the top-level threadId if present, otherwise messageData.threadId, otherwise use the messageId.
object
required
Message content and metadata

Optional Fields

string
Communication channel (defaults to STANDARD)
Available Values: STANDARD, EMAIL, EFORM, MICROSOFT_GRAPH, FAX_WEBHOOK, VOICE_TRANSCRIPT, TICKETING, JITBIT, JSON
Channel Types:
  • STANDARD - Default when channel is omitted
  • EMAIL - Email responses
  • EFORM - Electronic forms
  • MICROSOFT_GRAPH - Office 365
  • FAX_WEBHOOK - Fax responses
  • VOICE_TRANSCRIPT - Phone/voice transcription responses
  • TICKETING / JITBIT - Ticketing systems
  • JSON - Generic structured JSON payloads from upstream systems
object
Additional context data. Required fields depend on channel.

Attachments

Attachments are supported for PDF files. PDFs are automatically processed to extract text content, which is then used during message classification and verification data extraction. Supported Format:
  • PDF files (application/pdf) - Fully supported with text extraction
  • Other file types may be included but will not be processed
Attachment Processing:
  • PDFs are processed using document extraction tools
  • Extracted text is included in the message analysis
  • Processing errors are logged but do not block message processing

Response

string
Echo of the submitted message ID
boolean
Whether processing succeeded
object
AI-powered message classification
Fields:
  • type - Classification type (see Classification Types below)
  • confidence - Score from 0 to 1 indicating classification confidence
    - reasoning - Explanation of the classification decision
object
Root-level highest-confidence normalized employment verification object, omitted from extractedData. This temporary backward-compatible shape applies to every channel. Each object includes backward-compatible flat provided* / verified* values (including applicant names and providedReasonLeft) and the canonical fields comparison map. See the EmploymentVerification object for field definitions.
object
Education counterpart to root-level employmentVerification, omitted from extractedData. This is the single highest-confidence provider education-history object for every channel. Each object includes backward-compatible flat provided* / verified* values and the canonical fields comparison map. See the EducationVerification object for field definitions.
employmentVerification and educationVerification temporarily return one object for backward compatibility. A future version will return sorted arrays after consumers migrate to the array contract.
object
Structured verification data extracted from the message. Present on successful processing for every channel, including JSON. Does not include duplicate employmentVerification / educationVerification objects when those are returned at the response root.
array
Error messages if failed (empty array if successful)
object
Processing details including searchId, outcome, and channel
string
Processing completion timestamp (ISO 8601 format)

Classification Types

The classification type field is one of the INTENT enum values assigned by the inbound processing pipeline:
  • VERIFICATION - Verification confirmed with details
  • INFO_REQUEST - Employer/school needs more information, or a general information request
  • INFO_PROVIDED - Applicant provided information that may need follow-up
  • NEXT_CONTACT - Indicates a different contact at the entity should be reached next
  • WRONG_ENTITY - Message indicates the wrong organization/entity was contacted
  • RECORD_NOT_FOUND - No employment/education record found
  • AUTHORIZATION_FORM_REQUEST - Authorization form is needed before the entity will respond
  • NO_ACTION_REQUIRED - Message requires no further action
  • UNKNOWN - Could not determine intent
  • OTHER - Other classification that doesn’t fit the above
THIRD_PARTY is a deprecated legacy value — the classifier remaps it to WRONG_ENTITY internally, so it will never appear in a response’s classification.type.

Examples

Employment Verification

Success Response (non-JSON channels): Non-JSON successful submissions return a single root-level employmentVerification object with per-field comparison in fields (not nested in extractedData). Example from an EMAIL channel response for Pablo’s Pizza / John Smith:

Education Form Submission

Success Response:

Generic JSON Submission

Use channel: "JSON" when an upstream system sends structured third-party verification data instead of an email, fax, or ticket transcript. Place the provider payload in messageData.data. JSON channel requirements: JSON payloads may contain the full employment or education history returned by the provider. When multiple records are present, SNH AI includes the matched search’s applicant and submitted history context in extraction so the most relevant record can be identified, extracted, and compared to the submitted applicant data.

Supported JSON payload shapes

The API detects employment or education history records from common vendor response layouts. You do not need to normalize the payload to a single schema — pass the vendor object in messageData.data. Employment searches — records are enumerated from: Education searches — records are enumerated from:

Employment JSON example

Employment success response: HTTP 200 with the standard processing response body. extractedData contains the best-match scalars and operational flags, while root-level employmentVerification contains the single highest-confidence provider history object.

Education JSON example

Successful channel: "JSON" submissions return the same synchronous processing envelope as other channels: messageId, success, classification, extractedData, the applicable root-level employmentVerification / educationVerification object, metadata, and processedAt. The verification object is the highest-confidence provider history row. The employment example selects the row with confidence 0.94 for search EXT-DEV-1781042158637-1. The raw provider payload is not echoed in the synchronous response or webhook payloads. For the full verification.completed JSON closeout shape, see Webhook events — Employment Verification (JSON channel).

Comparison fields: selected JSON record

JSON channel responses expose comparison output at two levels:

Field comparison metadata (fields.*.comparison)

Normalized verification objects (for example employmentVerification.fields on downstream webhooks) attach per-field comparison metadata. similarity is not a universal score — deterministic exact string matches use similarity: 1, and probabilistic / organization-name comparisons use their evaluated score. Date and number fields never include similarity; deterministic matches and mismatches on those types use distance instead. Examples Location proximity mismatch:
Location proximity discrepancy:
Deterministic date match (distance: 0, no similarity):
LLM semantic discrepancy (similarity present):

Downstream webhook delivery

In addition to the synchronous response body, successful JSON submissions emit extraction and the selected normalized verification object asynchronously. Primary delivery paths:
  • verification.notification with notificationType: "INBOUND_RECEIVED_DETAIL" — best-match scalars (and optional applicantMismatch / _requiresManualReview flags) at data.metadata.extractedData; the highest-confidence record with per-field comparison at root-level data.employmentVerification or data.educationVerification (not nested in extractedData). applicantMismatches and applicantDiscrepancies are not included.
  • verification.action_required with reasonCode: "HUMAN_ESCALATION" or "OTHER" — when manual review is required for non-verified or JSON-channel holds; extractedData under data.metadata.extractedData without duplicate verification data. JSON-channel only (channel: "JSON", status: "QA Review"): root-level data.message (human-readable review summary for client UI) plus the highest-confidence data.employmentVerification or data.educationVerification object. EMAIL/FAX/VOICE action-required webhooks omit message. Verified EMAIL/FAX/VOICE with field mismatches typically close via verification.completed and verificationResult.discrepancy: true instead.
  • Activity metadata — root-level employmentVerification / educationVerification plus stripped extractedData (same split as webhooks), alongside messageId, threadId, contactType, and messageContext
  • verification.completed — root-level data.employmentVerification (or data.educationVerification) as the single highest-confidence object for JSON. data.verificationResult.extractedData keeps scalar extraction and comparison metadata without duplicate verification data. verificationResult.discrepancy is the operational closeout flag and may be false when the selected row only has non-critical fields.*.status: "match_with_discrepancy" entries.
The examples below show the INBOUND_RECEIVED_DETAIL webhook envelope for search 86bc0a43-6a10-4f85-a093-e4244ed78107 / EXT-DEV-1781042158637-1 (Pablo’s Pizza / John Smith). metadata.extractedData is identical wherever that object appears; the selected verification object sits at the payload root.
Note: For JSON, root-level employmentVerification / educationVerification is the highest-confidence object. Field-level comparison for that selected row appears on data.employmentVerification.fields / data.educationVerification.fields. applicantMismatches and applicantDiscrepancies are not included in webhook or inbound notification payloads — use fields.* instead. When a critical mismatch triggers escalation, metadata.extractedData may include applicantMismatch: true and _requiresManualReview: true without field-level objects. When the search closes without escalation, verification.completed may set verificationResult.discrepancy: false even though employmentVerification.fields.position.status is match_with_discrepancy — see Webhook events.

Auto-Generated IDs

When messageId or threadId are not provided, the system automatically generates them:

Error Responses

This endpoint always returns HTTP 200 (the controller forces @HttpCode(HttpStatus.OK)), even when processing fails. Failures are represented in the response body, not the HTTP status — check the success and failureReasons fields on every response.
Validation failures on this request return the same generic 400 Bad Request shape as every other endpoint — there is no 422 status configured for this API. messageId is optional and can never trigger a “should not be empty” failure; messageData.timestamp is the field actually marked as required.
Non-JSON channels also require messageData.from and messageData.to; the controller checks this explicitly and returns a single-string 400 message (not the array shape) naming the missing fields.

How It Works

The inbound notification processing follows these steps:
  1. Submit - You send verification response via API
  2. ID Generation - If messageId or threadId are not provided, they are auto-generated
  3. Validate - System validates required fields and checks for malicious content. For JSON channel, validates that metadata.searchRefId and a non-empty messageData.data payload are present. For other channels, validates messageData.from and messageData.to.
  4. Match - Links message to active verification search:
    • JSON channel: Matches exclusively on metadata.searchRefId (external search ID or internal reference). Does not scan the payload body for reference numbers.
    • Other channels: Extracts 7–8 digit reference numbers from subject, body, attachments, or uses metadata.searchRefId / threadId when provided.
  5. Process Attachments - PDF attachments are processed to extract text content (if present; skipped for JSON channel)
  6. Analyze Contact - Determines sender type (APPLICANT, ENTITY, or UNKNOWN). JSON channel requests are treated as ENTITY responses.
  7. Classify & Extract - AI-powered classification extracts verification details:
    • JSON channel: Extracts directly from structured provider payload; selects the best-matching employment or education record when multiple are present.
    • Other channels: Analyzes the message content to extract structured verification data.
    • Extracts structured outcome (VERIFIED, NO_RECORD, THIRD_PARTY, INFO_REQUESTED, etc.)
    • Parses verification data (dates, positions, confirmation status)
  8. Cross-check Provided Data - Compares extracted applicant, employment, or education details against the order data on file. Tenant comparison settings (see tenant config.comparisonConfig) tune behavior: calendar-day windows per date field (startDate, endDate, graduationDate), semantic equivalence thresholds for applicant name, job title, degree, major, and location proximity, and salary tolerances. For employment salary, when both the order value (providedSalary in search metadata) and the extracted salary parse, the API normalizes common compensation text (for example annual, hourly, monthly, weekly, and k / m suffixes) to an estimated annual USD amount and treats a mismatch only if the gap exceeds both the configured absolute-dollar threshold and the relative (percent) threshold; otherwise it falls back to the same normalized string comparison used for other plain-text fields. Mismatch reasons for dates and salaries include the compared raw values (and annualized figures for salary) to aid review.
  9. Persist Results - Saves processing results, classification, and extracted data
  10. Update Search - Updates search status if terminal outcome (VERIFIED, NO_RECORD, THIRD_PARTY, WRONG_ORG)
  11. Schedule Follow-up - If non-terminal outcome (INFO_REQUESTED, INSUFFICIENT), schedules next outbound attempt
  12. Notify - Sends webhook if verification reaches terminal state

Common Use Cases

Best Practices

Message IDs:
  • Use unique identifiers (UUIDs recommended) if available
  • Never reuse message IDs
  • Optional: Omit the field entirely if you don’t have one - the system will auto-generate it
  • If provided, ensure it’s unique across all messages
Thread IDs:
  • Keep consistent for related messages in the same conversation thread
  • Helps track conversation history across multiple exchanges
  • Optional: Omit the field entirely if you don’t have one - the system will use the messageId as the threadId
  • Use the same threadId for all messages in the same conversation
Timestamps:
  • Always use ISO 8601 format
  • Example: 2026-01-15T10:30:00.000Z
Content (email, fax, form, ticketing channels):
  • Include all verification details in the body.text field
  • Include reference number: The message must contain a 7-8 digit reference number to match the message to the correct verification search. The system looks for patterns like:
    • “Reference: 12345678”
    • “Ref. 12345678”
    • “Ticket # 12345678”
    • “Case # 12345678”
    • Or standalone 7-8 digit numbers
  • Mention attachments sent via separate channels if needed
Content (JSON channel):
  • Set channel to "JSON" and place the vendor response in messageData.data
  • Always include metadata.searchRefId — this is the only search-matching mechanism for JSON requests. Use the search’s external ID (e.g. EXT-DEV-1781042158637-1) or internal reference number
  • Set metadata.provider to identify the upstream system for audit and traceability
  • Pass the vendor payload as-is; normalization to a single schema is not required
  • When the provider returns multiple employment or education records, include all of them — the API selects the record that best matches the applicant and submitted search data
Error Handling:
  • For every channel, HTTP 200 includes a response body; check success and process failureReasons when present
  • Successful responses include best-match scalars in extractedData and the highest-confidence normalized provider record in the applicable root-level verification object
  • Implement retry with exponential backoff for server errors

Troubleshooting

“metadata.searchRefId is required for JSON channel requests”
  • Include metadata.searchRefId on every channel: "JSON" request
  • The value must be a non-empty string
“No JSON payload found”
  • Ensure messageData.data is a non-empty object containing at least one enumerable employment or education record
  • Do not send only { "text": "..." } or { "html": "..." } keys without structured verification data
“Search not found in verification system” (JSON channel)
  • Verify metadata.searchRefId matches the search’s externalSearchId or internal reference
  • Ensure the search is still active (not completed or cancelled)
  • Check that the search has the INBOUND objective enabled
“Search not found” (non-JSON channels)
  • Verify the message contains a valid 7-8 digit reference number in one of the supported formats:
    • “Reference: 12345678”
    • “Ref. 12345678”
    • “Ticket # 12345678”
    • “Case # 12345678”
    • Or a standalone 7-8 digit number
  • Ensure the reference number matches an active verification search
  • Ensure search is still active (not completed or cancelled)
  • Check that the search has the INBOUND objective enabled
  • Check sender email matches expected contact (if applicable)
“messageData.from, messageData.to required for channel”
  • Non-JSON channels require both messageData.from and messageData.to
  • These fields are optional only when channel is "JSON"
“Invalid message format”
  • All required fields must be present for the channel type
  • Check timestamp is valid ISO 8601
“Validation error”
  • Review error messages in response
  • Verify data types match requirements
  • Ensure all required fields are present

Next Steps

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Body

application/json
messageData
Message Data · object
required

Message data

messageId
string

Message ID to process (auto-generated if not provided)

threadId
string

Thread ID (auto-generated if not provided)

channel
enum<string>

Channel type

Available options:
MICROSOFT_GRAPH,
FAX_WEBHOOK,
STANDARD,
EMAIL,
TICKETING,
JITBIT,
EFORM
metadata
object

Additional metadata. Can include pre-extracted data from upstream systems: - provider: Source system identifier (e.g., 'SNH AI ', 'JITBIT') - searchRefId: Reference ID for the search - activityId: Activity ID from upstream system - link: URL to original ticket/message - intention: Pre-classified intent (VERIFICATION, INFO_REQUEST, THIRD_PARTY, etc.) - confidence: Confidence level from upstream (0-1). Defaults to 0.95 if not provided. - structuredData: Pre-extracted verification data with verifiedInfo and verificationResult

Example:

Response

200 - application/json

The response is of type object.