{"openapi":"3.1.0","info":{"title":"SignupVet API","version":"1.0.0","description":"Checks email, phone and IP of a signup and returns one risk score with reason codes."},"servers":[{"url":"https://www.signupvet.com"}],"security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"paths":{"/score":{"post":{"summary":"Combined signup score","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":320},"phone":{"type":"string","maxLength":64,"description":"International (+41…, 0041…) or national with country_hint."},"country_hint":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2 country code."},"ip":{"type":"string","description":"IPv4 or IPv6 address of the end user."},"context":{"type":"object","properties":{"timezone":{"type":"string","description":"Browser time zone, e.g. Europe/Zurich."},"user_agent":{"type":"string"},"referrer":{"type":"string"},"sign_up_source":{"type":"string"},"accept_language":{"type":"string"}}}},"anyOf":[{"required":["email"]},{"required":["phone"]},{"required":["ip"]}]}}}},"responses":{"200":{"description":"Check result.","content":{"application/json":{"schema":{"type":"object","required":["request_id","status","risk_score","risk_level","recommendation","reason_codes","signals","confidence","provider","latency_ms"],"properties":{"request_id":{"type":"string"},"status":{"type":"string","enum":["valid","invalid","risky","unknown"]},"risk_score":{"type":"integer","minimum":0,"maximum":100},"risk_level":{"type":"string","enum":["low","medium","high","critical"]},"recommendation":{"type":"string","enum":["allow","review","block"]},"reason_codes":{"type":"array","items":{"$ref":"#/components/schemas/ReasonCode"}},"signals":{"type":"object","properties":{"email":{"oneOf":[{"type":"object","properties":{"normalized_email":{"type":["string","null"]},"domain":{"type":["string","null"]},"syntax_valid":{"type":"boolean"},"mx_records_present":{"type":["boolean","null"]},"disposable_domain":{"type":"boolean"},"role_based":{"type":"boolean"},"catch_all":{"type":["boolean","null"]},"domain_age_days":{"type":["integer","null"]},"domain_reputation":{"type":["string","null"]}}},{"type":"null"}]},"phone":{"oneOf":[{"type":"object","properties":{"normalized_phone":{"type":["string","null"]},"format_valid":{"type":"boolean"},"country":{"type":["string","null"]},"line_type":{"type":["string","null"]},"carrier":{"type":["string","null"]},"is_voip":{"type":["boolean","null"]},"is_prepaid":{"type":["boolean","null"]}}},{"type":"null"}]},"ip":{"oneOf":[{"type":"object","properties":{"country":{"type":["string","null"]},"region":{"type":["string","null"]},"city":{"type":["string","null"]},"asn":{"type":["integer","null"]},"organization":{"type":["string","null"]},"is_datacenter":{"type":"boolean"},"is_proxy":{"type":["boolean","null"]},"is_vpn":{"type":"boolean"},"is_tor":{"type":"boolean"},"risk_categories":{"type":"array","items":{"type":"string"}}}},{"type":"null"}]},"pattern":{"oneOf":[{"type":"object","properties":{"same_ip_10m":{"type":"integer"},"same_network_10m":{"type":"integer"},"email_series_1h":{"type":"integer"},"same_domain_10m":{"type":"integer"},"phone_other_accounts_24h":{"type":"integer"}}},{"type":"null"}]}}},"confidence":{"type":"integer","minimum":0,"maximum":100},"provider":{"type":"string"},"latency_ms":{"type":"integer"},"policy":{"type":"object","properties":{"allow_threshold":{"type":"integer"},"review_threshold":{"type":"integer"},"block_threshold":{"type":"integer"}}}}}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Checks of the billing period are used up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/verify/email":{"post":{"summary":"Email check","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","maxLength":320},"ip":{"type":"string","description":"IPv4 or IPv6 address of the end user."},"context":{"type":"object","properties":{"timezone":{"type":"string","description":"Browser time zone, e.g. Europe/Zurich."},"user_agent":{"type":"string"},"referrer":{"type":"string"},"sign_up_source":{"type":"string"},"accept_language":{"type":"string"}}}}}}}},"responses":{"200":{"description":"Check result.","content":{"application/json":{"schema":{"type":"object","required":["request_id","status","risk_score","risk_level","recommendation","reason_codes","signals","confidence","provider","latency_ms"],"properties":{"request_id":{"type":"string"},"status":{"type":"string","enum":["valid","invalid","risky","unknown"]},"risk_score":{"type":"integer","minimum":0,"maximum":100},"risk_level":{"type":"string","enum":["low","medium","high","critical"]},"recommendation":{"type":"string","enum":["allow","review","block"]},"reason_codes":{"type":"array","items":{"$ref":"#/components/schemas/ReasonCode"}},"signals":{"type":"object","properties":{"normalized_email":{"type":["string","null"]},"domain":{"type":["string","null"]},"syntax_valid":{"type":"boolean"},"mx_records_present":{"type":["boolean","null"]},"disposable_domain":{"type":"boolean"},"role_based":{"type":"boolean"},"catch_all":{"type":["boolean","null"]},"domain_age_days":{"type":["integer","null"]},"domain_reputation":{"type":["string","null"]}}},"confidence":{"type":"integer","minimum":0,"maximum":100},"provider":{"type":"string"},"latency_ms":{"type":"integer"}}}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Checks of the billing period are used up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/verify/phone":{"post":{"summary":"Phone check","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","maxLength":64,"description":"International (+41…, 0041…) or national with country_hint."},"country_hint":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2 country code."},"ip":{"type":"string","description":"IPv4 or IPv6 address of the end user."},"context":{"type":"object","properties":{"timezone":{"type":"string","description":"Browser time zone, e.g. Europe/Zurich."},"user_agent":{"type":"string"},"referrer":{"type":"string"},"sign_up_source":{"type":"string"},"accept_language":{"type":"string"}}}}}}}},"responses":{"200":{"description":"Check result.","content":{"application/json":{"schema":{"type":"object","required":["request_id","status","risk_score","risk_level","recommendation","reason_codes","signals","confidence","provider","latency_ms"],"properties":{"request_id":{"type":"string"},"status":{"type":"string","enum":["valid","invalid","risky","unknown"]},"risk_score":{"type":"integer","minimum":0,"maximum":100},"risk_level":{"type":"string","enum":["low","medium","high","critical"]},"recommendation":{"type":"string","enum":["allow","review","block"]},"reason_codes":{"type":"array","items":{"$ref":"#/components/schemas/ReasonCode"}},"signals":{"type":"object","properties":{"normalized_phone":{"type":["string","null"]},"format_valid":{"type":"boolean"},"country":{"type":["string","null"]},"line_type":{"type":["string","null"]},"carrier":{"type":["string","null"]},"is_voip":{"type":["boolean","null"]},"is_prepaid":{"type":["boolean","null"]}}},"confidence":{"type":"integer","minimum":0,"maximum":100},"provider":{"type":"string"},"latency_ms":{"type":"integer"}}}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Checks of the billing period are used up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/verify/ip":{"post":{"summary":"IP check","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ip"],"properties":{"ip":{"type":"string","description":"IPv4 or IPv6 address of the end user."},"context":{"type":"object","properties":{"timezone":{"type":"string","description":"Browser time zone, e.g. Europe/Zurich."},"user_agent":{"type":"string"},"referrer":{"type":"string"},"sign_up_source":{"type":"string"},"accept_language":{"type":"string"}}}}}}}},"responses":{"200":{"description":"Check result.","content":{"application/json":{"schema":{"type":"object","required":["request_id","status","risk_score","risk_level","recommendation","reason_codes","signals","confidence","provider","latency_ms"],"properties":{"request_id":{"type":"string"},"status":{"type":"string","enum":["valid","invalid","risky","unknown"]},"risk_score":{"type":"integer","minimum":0,"maximum":100},"risk_level":{"type":"string","enum":["low","medium","high","critical"]},"recommendation":{"type":"string","enum":["allow","review","block"]},"reason_codes":{"type":"array","items":{"$ref":"#/components/schemas/ReasonCode"}},"signals":{"type":"object","properties":{"country":{"type":["string","null"]},"region":{"type":["string","null"]},"city":{"type":["string","null"]},"asn":{"type":["integer","null"]},"organization":{"type":["string","null"]},"is_datacenter":{"type":"boolean"},"is_proxy":{"type":["boolean","null"]},"is_vpn":{"type":"boolean"},"is_tor":{"type":"boolean"},"risk_categories":{"type":"array","items":{"type":"string"}}}},"confidence":{"type":"integer","minimum":0,"maximum":100},"provider":{"type":"string"},"latency_ms":{"type":"integer"}}}}}},"400":{"description":"Invalid request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Checks of the billing period are used up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit reached.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key from the dashboard (sv_live_…)."},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"}},"schemas":{"ReasonCode":{"type":"string","enum":["email_syntax_valid","email_syntax_invalid","mx_records_present","mx_records_missing","domain_rejects_mail","domain_not_found","disposable_domain","role_based_address","dns_lookup_failed","phone_format_valid","phone_format_invalid","phone_country_unknown","phone_country_mismatch","carrier_found","carrier_lookup_failed","line_type_mobile","line_type_fixed_line_or_mobile","line_type_landline","line_type_unknown","line_type_fixed_voip","line_type_voip","line_type_shared_cost","line_type_personal","line_type_uan","line_type_non_fixed_voip","line_type_toll_free","line_type_pager","line_type_voicemail","line_type_premium_rate","tor_exit_node","proxy_or_vpn_suspected","ip_datacenter_asn","ip_private_or_reserved","geo_mismatch","multiple_risk_signals","phone_ip_country_mismatch","signup_velocity_ip","email_series_pattern","signup_velocity_network","signup_velocity_domain","phone_reused"],"description":"email_syntax_valid: The address is syntactically valid.\nemail_syntax_invalid: The address is not a syntactically valid email address.\nmx_records_present: The domain publishes MX records.\nmx_records_missing: No MX records. With an A record the domain may still receive mail (35); with neither it cannot (90).\ndomain_rejects_mail: The domain publishes a null MX record (RFC 7505): it explicitly accepts no email.\ndomain_not_found: The domain does not exist in DNS.\ndisposable_domain: The domain belongs to a known throwaway email service.\nrole_based_address: A shared or functional mailbox rather than a person.\ndns_lookup_failed: DNS did not answer in time; the result is uncertain (status unknown).\nphone_format_valid: The number is valid for its country.\nphone_format_invalid: The number is not valid (wrong length or range).\nphone_country_unknown: A national number was sent without country_hint, so it cannot be validated.\nphone_country_mismatch: The number belongs to a different country than country_hint.\ncarrier_found: The carrier lookup identified the network operator.\ncarrier_lookup_failed: The carrier lookup was unavailable; the local result is used.\nline_type_mobile: Regular mobile number.\nline_type_fixed_line_or_mobile: Number range is shared by mobile and landline (e.g. US).\nline_type_landline: Landline; slightly unusual for signups.\nline_type_unknown: The number is valid but its type is unknown.\nline_type_fixed_voip: VoIP number tied to an address (carrier lookup only).\nline_type_voip: VoIP number range (local detection).\nline_type_shared_cost: Special service number.\nline_type_personal: Personal forwarding number.\nline_type_uan: Universal access number of a company.\nline_type_non_fixed_voip: Virtual number such as Google Voice (carrier lookup only).\nline_type_toll_free: Toll-free hotline, not a person.\nline_type_pager: Pager, not a person.\nline_type_voicemail: Voicemail-only number.\nline_type_premium_rate: Expensive premium-rate number.\ntor_exit_node: The IP is a Tor exit node.\nproxy_or_vpn_suspected: The IP belongs to a known VPN provider.\nip_datacenter_asn: The IP belongs to a datacenter or cloud network, not a home or mobile connection.\nip_private_or_reserved: A private or reserved IP. Usually your server sent its own address instead of the user's.\ngeo_mismatch: context.timezone does not belong to the IP's country.\nmultiple_risk_signals: Added once per further channel that is suspicious on its own (score ≥ 30).\nphone_ip_country_mismatch: The phone number and the IP address belong to different countries.\nsignup_velocity_ip: 3 or more earlier signups from the same IP within 10 minutes.\nemail_series_pattern: 2 or more other addresses of the same series (max1@, max2@ …) within 1 hour.\nsignup_velocity_network: 10 or more earlier signups from the same /24 (IPv4) or /48 (IPv6) network within 10 minutes.\nsignup_velocity_domain: 5 or more other addresses on the same company domain within 10 minutes (big mail providers excluded).\nphone_reused: The same phone number was used with a different email address within 24 hours."},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}}}}}}}}}}}