Skip to main content

SearchConfigDto Schema

SearchConfigDto captures per-search policy overrides. Omitted fields fall back to tenant policy, then system defaults. All top-level sections are optional, with one conditional requirement: research.skipResearch=true requires at least one outbound.contactHints[] entry with email, phone, or fax. It can be supplied in two places on a create-order request:
  • searchTypes[i].searchConfig — per-search overrides. When present (even as an empty {}), it fully replaces any request-level defaultSearchConfig for that search.
  • defaultSearchConfig — order-level default applied to every created search whose per-search searchConfig is absent.
Merge semantics are whole-object replace, not section-wise merge. If you set searchTypes[0].searchConfig = { channels: { email: true } }, only the channels override is applied for that search; timing, outbound, etc. revert to tenant/system defaults — they are not inherited from defaultSearchConfig.

Fields

Most integrations only need one or two sections at a time. Common starting points:
  • Use channels to prefer or disable outbound channels.
  • Use timing to tune SLA and business-hours behavior.
  • Use outbound.contactHints with research.skipResearch=true when you already know the right verification contact and want to bypass automated research.
  • Use notifications when a specific search needs different webhook routing from the rest of the order.
Example — email-only outbound with a blocked generic inbox
{
  "channels": {
    "email": true,
    "voice": false,
    "fax": false,
    "preferredChannel": "EMAIL",
    "blockedDestinations": ["hr-noreply@company.com"]
  }
}
Example — weekday 9–5 Central with a 48h SLA
{
  "timing": {
    "searchSlaMinutes": 2880,
    "outboundWindowMinutes": 120,
    "businessHours": {
      "timezone": "America/Chicago",
      "startTime": "09:00",
      "endTime": "17:00",
      "allowedDays": [1, 2, 3, 4, 5]
    }
  }
}
Example — attempt caps plus a high-priority pre-known contact
{
  "outbound": {
    "maxAttemptsPerMethod": 5,
    "maxTotalAttempts": 12,
    "cancelOutboundOnTerminalInbound": true,
    "contactHints": [
      {
        "name": "Jane Doe",
        "title": "HR Director",
        "email": "jane.doe@company.com",
        "phone": "+1 (555) 123-4567",
        "priority": "HIGH"
      }
    ]
  }
}
Example — skip research and rely on a pre-known contact
{
  "research": { "skipResearch": true },
  "outbound": {
    "contactHints": [
      { "email": "verify@company.com", "priority": "HIGH" }
    ]
  }
}
Data-model implication when inbound is held for QA.When requireManualReview=true or autoCompleteOnVerification=false routes a verified inbound to QA, the persisted VerificationResult.outcome is set to ACTION_REQUIREDnot the extracted terminal outcome (VERIFIED, NO_RECORD, etc.). The extracted outcome is preserved in the activity/metadata trail for reviewers, but downstream consumers that read VerificationResult.outcome before QA resolution will see ACTION_REQUIRED. Once QA completes the manual review path, the outcome is updated to reflect the final decision.If your integration assumes VerificationResult.outcome always mirrors the inbound response, either leave autoCompleteOnVerification=true or wait for the subsequent verification.completed event before reading the outcome.
Example — route every verified inbound to QA
{
  "inbound": { "requireManualReview": true }
}
Example — email-only outbound even when research flags a third-party vendor
{
  "channels": {
    "email": true,
    "voice": false,
    "fax": false,
    "preferredChannel": "EMAIL"
  },
  "escalation": {
    "disableThirdPartyEvent": true
  }
}
Example — per-search webhook override that only routes completions
{
  "notifications": {
    "suppressNotifications": true,
    "webhookOverride": {
      "enabled": true,
      "secret": "s3cret-per-search",
      "retryAttempts": 3,
      "closeoutEndpoints": {
        "EMPLOYMENT": [
          {
            "url": "https://client.example.com/webhooks/employment-closeout",
            "events": ["verification.completed"]
          }
        ]
      }
    }
  }
}

Complete Example

A SearchConfigDto combining most sections, as you might attach to a single search:
{
  "channels": {
    "email": true,
    "voice": false,
    "preferredChannel": "EMAIL",
    "blockedDestinations": ["hr-noreply@company.com"]
  },
  "timing": {
    "searchSlaMinutes": 2880,
    "outboundWindowMinutes": 120,
    "businessHours": {
      "timezone": "America/Chicago",
      "startTime": "09:00",
      "endTime": "16:00",
      "allowedDays": [1, 2, 3, 4, 5]
    }
  },
  "outbound": {
    "maxAttemptsPerMethod": 5,
    "maxTotalAttempts": 12,
    "cancelOutboundOnTerminalInbound": true,
    "contactHints": [
      { "email": "hr@company.com", "priority": "HIGH" }
    ]
  },
  "research": { "skipResearch": false }
}
Attached to a create-order request either as a per-search override or an order-level default:
{
  "defaultSearchConfig": {
    "timing": { "outboundWindowMinutes": 120 }
  },
  "searchTypes": [
    {
      "searchType": "EMPLOYMENT",
      "searchConfig": {
        "channels": { "email": true, "preferredChannel": "EMAIL" },
        "outbound": {
          "contactHints": [{ "email": "hr@company.com", "priority": "HIGH" }]
        }
      }
    },
    { "searchType": "EDUCATION" }
  ]
}
In this request:
  • The EMPLOYMENT search gets its per-search overrides — defaultSearchConfig is not merged in (e.g. outboundWindowMinutes falls back to tenant policy, not to 120).
  • The EDUCATION search has no per-search searchConfig, so it uses defaultSearchConfig (outboundWindowMinutes: 120 on top of tenant policy).

Validation Highlights

  • channels.blockedDestinations and channels.allowedDestinations are mutually exclusive; each is capped at 100 entries.
  • Each outbound.contactHints[] entry must include at least one of email, phone, or fax; max 50 hints.
  • timing.businessHours.startTime must be strictly earlier than timing.businessHours.endTime; allowedDays values must be in 0–6.
  • timing.businessHours.timezone must be a valid IANA timezone (validated via Intl.DateTimeFormat).
  • inbound.requireManualReview: true combined with inbound.autoCompleteOnVerification: false is rejected at validation time — omit autoCompleteOnVerification or set it to true.
  • escalation.escalationWebhookUrl and any URL fields inside notifications.webhookOverride are validated as URLs.
  • research.skipResearch: true requires outbound.contactHints with at least one reachable contact (email, phone, or fax) and bypasses the research agent at runtime. Channel-disabled contact methods are auto-suppressed.
  • Unknown fields on searchConfig are not part of the public contract and may be ignored by runtime policy resolution; send only the fields documented above.

Behavior Precedence

Once a search is created, the runtime resolves its effective policy by layering tenant defaults under the per-search overrides. These precedence rules apply at runtime:
  • Escalation gating: escalation.disableAutoEscalation=true wins over tenant-level humanEscalation.enabledForSource. When disableAutoEscalation=false (or omitted), the per-source tenant flag is consulted.
  • Escalation webhook routing: notifications.webhookOverride > escalation.escalationWebhookUrl > tenant webhook config. Set one or the other, not both.
  • Inbound terminal routing: inbound.requireManualReview=true routes verified inbounds to ACTION_REQUIRED regardless of autoCompleteOnVerification. When requireManualReview=false, autoCompleteOnVerification=false holds the search for QA as ACTION_REQUIRED; autoCompleteOnVerification=true (default) auto-completes.
  • Outbound cancel on terminal inbound: a pending third-party task always cancels outbound, regardless of outbound.cancelOutboundOnTerminalInbound.
  • Organization preferences: applied after per-search channel overrides. An org-level channel block still suppresses a channel that searchConfig.channels.* enables — this is a safety rail.
  • Notification suppression: notifications.suppressNotifications only affects intermediate verification.notification events. Terminal verification.completed and verification.action_required always fire.
  • Raw inbound stripping: only applied when notifications.includeRawInboundInWebhook is explicitly false. Tenants that have not set the flag retain current behavior.

Merge Semantics

  • When searchTypes[i].searchConfig is undefined or null, defaultSearchConfig applies for that search.
  • When searchTypes[i].searchConfig is present — including {} — it fully replaces defaultSearchConfig for that search. Section-wise merging is not performed.