Understanding Sandbox and Production Environments

Check provides two separate environments to support your integration journey: Sandbox for development and testing, and Production for live payroll operations. While we strive to keep these environments aligned, there are important differences you should understand when building a robust integration.

What is the Sandbox Environment?

The sandbox environment is a safe testing space where you can:

  • Develop and test your Check integration
  • Experiment with API calls without affecting real companies or employees
  • Validate workflows before going live
  • Train your team on Check's features

Important Differences to Know

Company Setup and Onboarding

Sandbox has automatic company status progression to help you see all lifecycle stages:

  • Companies automatically advance through implementation status phases every 2 minutes
  • The full implementation status lifecycle is: needs_attentionin_reviewcompleted
  • Additionally, each entity (company, employee, contractor) has an onboard.status (blocking, needs_attention, or completed) that determines whether payroll can run. These statuses do not automatically advance but must instead be advanced by resolving blockers, which are stored in onboard.remaining_steps and onboard.blocking_steps.

Validation rules relaxed in sandbox:

  • EIN/FEIN verification:
    • All EIN verifications automatically succeed in sandbox. In production, the real IRS verification runs — after 3 failed attempts, the EIN reaches final_rejected status and cannot be retried
    • To simulate EIN verification failure, create a company where both conditions are true:
      • legal_name starts with reject-fein-verification (e.g., "reject-fein-verification-test")
      • federal_ein starts with 12-345678 (e.g., "12-3456789")
      • Both sentinel values must match — if only one is set, the verification will auto-succeed as normal. When both match, the sandbox skips real verification and auto-rejects instead:
        • Attempts 1 and 2: Status is set to rejected (retryable — your integration should prompt the user to correct their info and try again)
        • Attempt 3: Status is set to final_rejected (permanent — no more retries allowed, the company cannot proceed without Check support intervention)
      • This lets you test the full rejection lifecycle and verify your integration handles both the retryable and terminal states.
  • Bank account verification: Company bank accounts are automatically set to ownership_verified and employee accounts to validated. In production, this process takes ~3 banking days via ACH prenote. Use routing number 000000000 to simulate a disabled bank account in sandbox, or 111111111 to simulate failure for both company and employee accounts.
  • Payroll approval gating: In sandbox, payrolls can run even if the company or employees have blocking onboard statuses. In production, payroll is blocked for any participant with onboard.status = "blocking".

Common blocking onboard requirements (enforced in production, skipped in sandbox by default):

For companies:

  • bank_account — bank account must exist, be verified (ownership_verified), and have a debit authorization submitted
  • setup_parameters — federal and state tax parameters must be fully configured
  • filing_authorization — federal and state filing authorization forms must be submitted

What this means for you: Companies that succeed in sandbox may encounter validation failures in production. If you want sandbox to enforce production-like payroll approval gating, reach out to your Check representative to enable the feature flag on your account.

Example production-only error responses:

When a company has incomplete onboarding:

{
  "error": {
    "type": "invalid_request_error",
    "code": "company_blocking",
    "message": "Company has blocking onboard requirements: bank_account, filing_authorization"
  }
}

When EIN verification is permanently rejected (after 3 failed attempts):

{
  "error": {
    "type": "invalid_request_error",
    "code": "federal_ein_verification_rejected",
    "message": "Federal EIN verification has reached final_rejected status and cannot be retried"
  }
}

When an employee has a blocking onboard status:

{
  "error": {
    "type": "invalid_request_error",
    "code": "employee_blocking",
    "message": "Employee has blocking onboard requirements that must be resolved before running payroll"
  }
}

Risk and Compliance

  • Companies are automatically approved for risk reviews in sandbox as compliance checks are bypassed

What risk review looks like in production:

When a company is submitted for enrollment, Check performs KYB (Know Your Business) verification. The company’s implementation.status will be in_review during this period, which can take up to 2 business days. If a risk issue is identified:

  • The company’s in_good_standing field is set to false, which prevents payroll from running
  • Conditions that can trigger this include: compliance_risk, fraud_risk, credit_risk, failed_debit, and late_wire
  • Attempting to run payroll for an affected company returns a company_blocking error
  • If KYB is fully denied, implementation.status will not advance to completed

Sandbox limitations: There is no simulation endpoint to trigger a risk review block. To prepare your integration:

  • Handle the in_good_standing = false state on the company object
  • Display appropriate messaging when company_blocking or company_not_implemented errors are returned
  • Direct users to contact support for risk holds — resolution requires Check intervention

Example: Company blocked by risk review:

{
  "error": {
    "type": "invalid_request_error",
    "code": "company_blocking",
    "message": "Company is not in good standing"
  }
}

The company object will show "in_good_standing": false and the standing conditions array will contain the specific reason (e.g., "compliance_risk", "fraud_risk", "credit_risk").

What this means for you: You cannot fully test risk review workflows in sandbox. Design your user experience for these scenarios upfront and verify your error handling covers company_blocking before going live

Money Movement

Sandbox simulates all payment processing meaning no real money moves through banks and physical checks are not printed.

How it works:

AspectSandboxProduction
Payment processingSimulated (auto-completes)Real ACH processing
Payment simulationAvailable via the start processing endpointNot available
Money movementNo - simulatedYes - real transfers
Failed payment testingAvailable via the fail funding endpointReal payment failures

What this means for you: Use our simulate endpoints to test various payment scenarios.

Simulating a full payroll payment lifecycle in sandbox:

  1. Create and approve a payroll (status becomes pending)
  2. Either wait for auto-transition (every 5 minutes, for approved payrolls only), or manually control each step:
    • Set sandbox_simulation_mode = "manual" on the payroll to disable auto-transitions
    • POST /payrolls/{id}/simulate/start_processing → status: processing
    • POST /payrolls/{id}/simulate/complete_funding → status: paid

Auto-transitions apply to approved payrolls only — if you need to inspect a specific intermediate state, switch to manual mode before approving.

Simulating specific failure modes:

  • NSF (Non-Sufficient Funds): Create a company with trade_name = "NSF Co." or "No Account Co." — triggers an R01 (Insufficient Funds) ACH return
  • Failed employee disbursement: Create an employee with first_name = "Barry" and last_name = "BadAccount" — triggers an R03 (No Account/Unable to Locate) ACH return
  • Predicted funding failure (NSF bucketing): Create a company with trade_name = "High Risk Co." or "High Risk Missing Co." — triggers the predicted funding failure flow, simulating Check's NSF risk model flagging a company before the debit is sent
  • Failed funding: Call POST /payrolls/{id}/simulate/fail_funding after the payroll reaches processing status

Payment reversals:

In sandbox, payment reversals are simulated instantly — a dummy reversal object is created and the payment is immediately marked as reversed, with no bank interaction. In production, reversals are submitted as real ACH reversal requests through the payment processor, and settlement timing depends on the banking network (typically 1–2 business days). Design your integration to handle the asynchronous nature of production reversals rather than assuming the instant sandbox behavior

Validation Rules

Sandbox has fewer validation rules to make testing easier.

Duplicate detection:

Sandbox does not enforce duplicate validation at the platform level. In production:

  • FEIN: Duplicate federal EINs across companies are detected and flagged
  • SSN: Employees with duplicate SSNs across the platform generate a duplicate_ssn blocked filing reason, which can prevent tax filings from being submitted

Blocking validation enforcement:

In sandbox, blocking validations are not enforced — validation failures that would raise hard exceptions in production instead log warnings and allow the operation to proceed. For example, a child support garnishment missing a required SDU (State Disbursement Unit) configuration will fail with an error in production, but silently pass in sandbox. This can mask configuration issues that only surface after go-live.

Field-level validation differences:

  • Some fields accept any value in sandbox (e.g., EIN format is not strictly validated) but have format constraints in production
  • SSN format validation rules are identical in both environments: invalid SSNs (starting with 9, 666, or 000; middle digits of 00; last four digits of 0000; or sequential/repeated patterns) are rejected in both environments

What this means for you: Implement your own validation logic even if sandbox accepts your data. Production enforces all blocking validations, and partners regularly encounter issues at go-live that were not surfaced in sandbox testing. See the Company Setup and Onboarding section above for the full list of blocking onboard requirements and how to enable production-parity payroll approval gating in sandbox

Feature Availability

Features can be enabled independently in each environment:

  • New features often roll out to production after sandbox testing
  • Some features require explicit enablement in your sandbox account

Common features that need explicit enablement (contact your Partner Engineer or Growth Manager):

  • Processing periods: two_day and one_day ACH processing must be enabled by Check
  • Payment methods: Paper checks, same-day ACH, and wire funding availability depend on your contract
  • Third-party partner integrations: Vestwell (401k), SimplyInsured (health insurance), and Next Insurance (workers' comp) each require a contract amendment and Check-side configuration
  • Tax jurisdictions: Sandbox supports all US states and jurisdictions by default, but production restricts operations to a specific set of ~50 supported states. If you build and test with a state in sandbox that isn't yet supported in production, you'll encounter errors at go-live. Verify your required jurisdictions are production-enabled before launch.

There is no self-serve API endpoint to check which features are enabled in your account. Before going live, verify with your Growth Manager or Partner Engineer that all features your integration relies on are active in production

Time-Dependent Logic

Sandbox auto-processes payrolls without enforcing real timing constraints, but production has strict funding deadlines you need to account for.

Production ACH funding deadlines:

Processing PeriodApproval Deadline
three_day3:00 PM ET, 3 banking days before pay date
two_day8:00 PM ET, 2 banking days before pay date
one_day8:00 PM ET, 1 banking day before pay date

Wire funding deadlines:

  • Payrolls funded by wire must be approved by 4:00 PM ET on pay date
  • Wires not received by 12:30 PM ET on pay date will cause the payroll to automatically fail
  • A failed wire adds a late_wire standing condition to the company, blocking future payrolls until resolved

Example: Payroll approved past deadline:

{
  "error": {
    "type": "invalid_request_error",
    "code": "payroll_approval_deadline_passed",
    "message": "The approval deadline for this payroll has passed. The pay date must be updated."
  }
}

Approximating time-dependent behavior in sandbox:

  • Use POST /payrolls/{id}/simulate/start_processing and POST /payrolls/{id}/simulate/complete_funding to manually step through payroll states without waiting for real deadlines
  • Use POST /payrolls/{id}/simulate/fail_funding to test the wire failure / late wire flow
  • There are no sandbox configuration options to adjust auto-progression timing

What this means for you: Design your integration to handle funding deadline scenarios. Communicate cutoff times clearly to your users and build alerting for payrolls approaching their approval deadlines.

Third-Party Partnerships

Integrations with Check’s ecosystem partners vary in their sandbox testability. All partner integrations require a contract amendment and Check-side configuration before testing in sandbox or deploying to production.

PartnerTypeSandbox Testable?Notes
Vestwell (401k)ComponentRequires setupCheck must configure Vestwell staging environment. You can read more about the transition from Accrue here.
SimplyInsured (Health Insurance)ComponentRequires setupCheck must stage the integration in SimplyInsured. Allow up to 2 weeks. May require a contract amendment.
Next Insurance (Workers’ Comp)ComponentAvailable with dummy dataTest data inputs are available to go through the full quote funnel. Requires Check setup; allow up to 2 weeks. May require a contract amendment.

What this means for you: Contact your Check account team early if you plan to integrate any ecosystem partners — setup can take 2+ weeks.

API Keys and Authentication

Each environment has completely separate authentication:

Sandbox:

  • Use sandbox API keys
  • Points to sandbox.checkhq.com
  • Data is completely isolated from production

Production:

  • Use production API keys
  • Points to api.checkhq.com
  • Processes real payroll for real companies

Never mix credentials between environments.

Webhook Handling

Webhooks behave differently in each environment. Sandbox webhooks may be slower to deliver than production which have higher throughput capacity. Webhook configs are also kept isolated so there is no cross-environment webhook delivery.

Retry logic comparison:

AspectSandboxProduction
Retry attempts1 retryUp to 18 attempts
Retry durationAfter 1 retry, abandoned~47 hours with exponential backoff
Initial wait10 seconds10 seconds
Max wait between retries6 hours6 hours
Check-Live header"false""true"

Using the Check-Live header:

All webhook events include a Check-Live header with value "false" in sandbox and "true" in production. Use this to gate real-money logic in your webhook handler so that a single handler can safely serve both environments:

app.post('/webhooks/check', (req, res) => {
  const isLive = req.headers['Check-Live'] === 'true';
  if (isLive) {
    // Handle real production event
  } else {
    // Handle sandbox test event
  }
});

Webhook delivery during sandbox inactivity: Sandbox webhook delivery does not queue indefinitely. If your endpoint is unavailable during sandbox testing, events are abandoned after the single retry and are not recoverable — use the manual retry API to redeliver specific events.

Webhook event types: The set of webhook topics and event types is identical between sandbox and production — there are no events that only fire in one environment. The same topics (e.g., payroll, payment, employee, company) and event types (created, updated, deleted, status_change) are available in both environments. The differences between environments are purely operational (delivery behavior, retry policies, and development convenience endpoints like the manual retry API).

Webhook config auto-disable: Check automatically disables webhook configs that consistently fail delivery. In sandbox, configs are disabled after 1 day of continuous failures. In production, the lookback window is 7 days. If your sandbox webhook endpoint goes down briefly during development, your config may be auto-disabled faster than you'd expect — check the active field on your webhook config if you stop receiving events.

Design recommendations:

  • Don't hardcode webhook timing assumptions
  • Implement robust retry logic for all webhook-triggered workflows (don't rely on Check's retry logic alone)
  • Monitor webhook delivery status via the API
  • Test webhook failures using the manual retry API in sandbox

Tax Filings and Tax Payments

Tax filing and tax payment behavior differs significantly between environments. In sandbox, filings can be generated and their lifecycle simulated, but critical production-only processes do not run.

Production-only processes (do not run in sandbox):

  • Filing sync: The workflow that syncs filing data with tax agencies runs only in production. Sandbox filings exist in Check's system but are never transmitted to any tax authority.
  • Employee tax statement publishing: W-2s, 1099s, and other employee tax statements are only published and synced in production.
  • Tax payment orchestration: Actual tax payments to agencies (federal, state, local) are only processed in production. Sandbox tax liabilities are calculated but no money is remitted.
  • Tax payment monitoring: Alerts for failed or late tax payments only fire in production.

What you can test in sandbox:

  • Verifying that your integration correctly reads filing status and blocked reasons
  • Reading filing data and tax liability calculations (these are computed in both environments)

What this means for you: You can test your integration's handling of filing status changes and blocked reasons in sandbox, but you cannot verify end-to-end filing submission or tax payment flows. Ensure your integration handles the blocked filing status and displays blocked reasons to users, as these are common in production (e.g., duplicate_ssn, missing tax parameters).

Sandbox-Only API Endpoints

These endpoints are only available in sandbox and return 404 in production:

EndpointPurpose
[Sandbox] Start processingSimulate starting payroll processing (pending → processing); requires sandbox_simulation_mode = manual
[Sandbox] Complete fundingSimulate successful funding settlement (processing → paid); requires sandbox_simulation_mode = manual
[Sandbox] Complete disbursementsSimulate disbursement completion; requires processing status
[Sandbox] Fail fundingSimulate funding failure; works on processing, paid, or partially_paid payrolls
Retry webhook event in sandboxRetry a failed webhook delivery for testing

Rate Limits and Data Constraints

Rate limits are identical in sandbox and production:

  • 25 requests per second per partner (across all API keys)
  • 100 concurrent in-flight requests per partner

When limits are exceeded, the API returns HTTP 429 with a Retry-After header and error type throttled.

Payroll data limits (same in both environments):

  • Maximum 500 payroll items (employees) per payroll
  • Maximum 500 contractor payments per payroll
  • Three-day processing payrolls: $1,000,000 maximum; above this, wire funding is required
  • Federal tax liability: $100,000 per deposit period maximum before wire funding is required

Sandbox data retention: Sandbox data is not periodically purged — records persist until explicitly deleted via the API. There is no enforced limit on the number of companies, employees, or payrolls you can create in sandbox.


Pre-Production Checklist

Before going live, verify the following:

Authentication & Configuration

  • Update API base URL from sandbox.checkhq.com to api.checkhq.com
  • Replace sandbox API keys with production API keys
  • Register webhook endpoints in the production environment

Integration Verification

  • Confirm all required features are enabled in production (contact your Partner Engineer or Growth Manager)
  • Verify third-party partner integrations are fully configured for production
  • Remove or guard all calls to sandbox-only simulation endpoints

Error Handling

  • Implement handling for company_blocking errors (incomplete onboarding, risk holds, standing issues)
  • Handle in_good_standing = false and display standing conditions to users
  • Handle EIN verification failures and the final_rejected state
  • Handle bank account verification delays (~3 banking days in production)
  • Handle onboard.status = "blocking" for employees and contractors before running payroll
  • Implement retry logic for webhook processing (don't rely on Check's retry alone — sandbox only retries once)
  • Handle payment reversal asynchronously (instant in sandbox, 1–2 business days in production)
  • Handle filing blocked statuses and display blocked reasons (e.g., duplicate_ssn)

UX Design

  • Design UX for risk review states (implementation.status = in_review) — can take up to 2 business days
  • Display funding deadlines to users and communicate approval cutoffs
  • Handle the full company implementation lifecycle: needs_attentionin_reviewcompleted
  • Use the Check-Live header in your webhook handler to distinguish sandbox from production events
  • Design for the case where a state/jurisdiction is not yet supported in production

For more information on the differences between sandbox and production, reach out to your Partner Engineer.