Skip to main content

Integration Scenarios

End-to-end test scripts for validating your Zenoo integration. Run these against the staging environment before going live.
Replace {project_hash} with your staging project hash and staging-key with your staging API key in all examples below.

Scenario 1: Company Verification sync end-to-end

Submit a company for verification using sync mode and validate the response.
# Submit company verification (sync)
curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -H "X-SYNC-TIMEOUT: 30000" \
  -d '{
    "company_name": "Test Company Clean Ltd",
    "registration_number": "TEST001",
    "country": "GB",
    "external_reference": "e2e-kyb-sync-001"
  }' | jq .
Verify the response contains:
  • overall_verdict is "Pass", "Refer", or "Fail"
  • risk_tier is "Low", "Medium", or "High"
  • company.legal_name is populated
  • company.verification_status is "Verified"
  • screening object contains pep_status, sanctions_status, adverse_media_status
  • checks_summary.total is greater than 0
  • case_reference starts with "AML-"
# Validate response fields
RESPONSE=$(curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -H "X-SYNC-TIMEOUT: 30000" \
  -d '{"company_name":"Test Company Clean Ltd","registration_number":"TEST001","country":"GB","external_reference":"e2e-kyb-sync-001"}')

echo "$RESPONSE" | jq '{
  verdict: .overall_verdict,
  risk: .risk_tier,
  company_verified: .company.verification_status,
  checks_total: .checks_summary.total,
  pep: .screening.pep_status,
  sanctions: .screening.sanctions_status
}'

Scenario 2: Person Verification async end-to-end

Initiate an async Person Verification journey, extract tokens, and poll for results.
# Step 1: Initiate async journey
INIT_RESPONSE=$(curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/init" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -d '{
    "first_name": "Test",
    "last_name": "Clean",
    "date_of_birth": "1990-01-15",
    "country": "GB",
    "external_reference": "e2e-kyc-async-001"
  }')

echo "Init response:"
echo "$INIT_RESPONSE" | jq .

# Step 2: Extract pull token
PULL_TOKEN=$(echo "$INIT_RESPONSE" | jq -r '.tokens.pull')
echo "Pull token: $PULL_TOKEN"

# Step 3: Poll for results (may return 204 while processing)
sleep 10
RESULT=$(curl -s -w "\n%{http_code}" \
  "https://instance.staging.onboardapp.io/api/gateway/sharable-payload/$PULL_TOKEN")

HTTP_CODE=$(echo "$RESULT" | tail -1)
BODY=$(echo "$RESULT" | head -n -1)

if [ "$HTTP_CODE" = "200" ]; then
  echo "Results ready:"
  echo "$BODY" | jq .
elif [ "$HTTP_CODE" = "204" ]; then
  echo "Still processing. Poll again in 30 seconds."
elif [ "$HTTP_CODE" = "404" ]; then
  echo "Token invalid or expired."
fi
Verify:
  • Init response contains tokens.pull and tokens.start
  • Poll returns 204 (processing) or 200 (results ready)
  • Final 200 response contains overall_verdict and risk_tier

Scenario 3: Idempotency

Submit the same external_reference twice. The second request should return the existing case, not create a duplicate.
REFERENCE="e2e-idempotent-$(date +%s)"

# First request
echo "--- First request ---"
curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -H "X-SYNC-TIMEOUT: 30000" \
  -d "{
    \"company_name\": \"Test Company Clean Ltd\",
    \"registration_number\": \"TEST001\",
    \"country\": \"GB\",
    \"external_reference\": \"$REFERENCE\"
  }" | jq '{case_reference: .case_reference, verdict: .overall_verdict}'

# Second request (same external_reference)
echo "--- Second request ---"
curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -H "X-SYNC-TIMEOUT: 30000" \
  -d "{
    \"company_name\": \"Test Company Clean Ltd\",
    \"registration_number\": \"TEST001\",
    \"country\": \"GB\",
    \"external_reference\": \"$REFERENCE\"
  }" | jq '{case_reference: .case_reference, verdict: .overall_verdict}'
Verify:
  • Both responses return the same case_reference
  • No duplicate verification is created
  • The second request completes faster (returns cached result)

Scenario 4: Error handling

Test error responses for common failure modes.

Missing required field (400)

curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -H "X-SYNC-TIMEOUT: 15000" \
  -d '{"country": "GB"}' | jq .
Expected: 400 with error: "VALIDATION_ERROR".

Invalid API key (401)

curl -s -w "\nHTTP %{http_code}" -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: invalid-key-here" \
  -H "X-SYNC-TIMEOUT: 15000" \
  -d '{"company_name":"Test","registration_number":"TEST001","country":"GB"}'
Expected: 401 with error: "UNAUTHORIZED".

Invalid project hash (404)

curl -s -w "\nHTTP %{http_code}" -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/invalid-hash/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -H "X-SYNC-TIMEOUT: 15000" \
  -d '{"company_name":"Test","registration_number":"TEST001","country":"GB"}'
Expected: 404 with error: "NOT_FOUND".

Invalid JSON (400)

curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -d 'this is not json' | jq .
Expected: 400 with error: "INVALID_JSON".

Scenario 5: Webhook delivery

Submit a verification and confirm your webhook endpoint receives the event.

Setup

Before running this test, ensure your staging webhook URL is configured. For local development:
# Terminal 1: Start your webhook listener
node -e "
const http = require('http');
const server = http.createServer((req, res) => {
  let body = '';
  req.on('data', chunk => body += chunk);
  req.on('end', () => {
    console.log('Webhook received:', JSON.stringify(JSON.parse(body), null, 2));
    res.writeHead(200);
    res.end('OK');
  });
});
server.listen(3000, () => console.log('Listening on port 3000'));
"

# Terminal 2: Expose via ngrok
ngrok http 3000
# Note the https URL and configure it as your staging webhook endpoint

Submit verification

# Submit a company verification to trigger a webhook
curl -s -X POST \
  "https://instance.staging.onboardapp.io/api/gateway/execute/{project_hash}/api" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: staging-key" \
  -H "X-SYNC-TIMEOUT: 30000" \
  -d '{
    "company_name": "Test Company Clean Ltd",
    "registration_number": "TEST001",
    "country": "GB",
    "external_reference": "e2e-webhook-001"
  }'

Verify webhook received

Check your webhook listener for a verification.completed event. The payload should include:
  • event_type: "verification.completed"
  • callback_reference matching your external_reference
  • data object with the full verification results
  • X-Zenoo-Signature header for signature verification

Verify signature

const crypto = require("crypto");

function verifyWebhookSignature(payload, signature, secret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(payload).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Checklist

Run all five scenarios and confirm:
  • Scenario 1: Sync Company Verification returns a complete compliance report
  • Scenario 2: Async Person Verification init returns tokens, poll returns results
  • Scenario 3: Duplicate external_reference returns same case
  • Scenario 4: All four error cases return correct status codes
  • Scenario 5: Webhook received with valid signature

Next steps