pixellint

AppsFlyer web visits validate their captured endpoint contracts.

The web visit operation belongs to events.appsflyer.com/v2.0/s2s/visits/app/web/{appId}. Its payload rules require captured HTTP endpoint context. Bare JSON cannot establish this operation, and the mobile S2S body remains a separate contract.

A top-level user_id object must contain customer_user_id, appsflyer_id or both. event_url is required and must be an HTTP or HTTPS URL of at most 4,096 characters. Unknown fields and custom parameters remain open.

Observed requests require POST, application/json and a populated Authorization Bearer token. Unavailable or redacted evidence is deferred. Live token/app ownership, late-arrival configuration, prior visits and hash preimages remain external.

The explicit endpoint tables require top-level user_id. A separate integration paragraph describes a conflicting nested wrapper. These checks follow the endpoint tables, document that conflict, and do not silently accept a nested alias or claim complete receiver acceptance.

At least one supported identity is required.

An empty user_id object has no supported identity. Either customer_user_id or appsflyer_id is sufficient; supplied values retain native string and length checks. The pack does not infer a UUID grammar or a prior identified session.

Rule: vendor.appsflyer-web-visit.http.user_id.identifier_required

A hash must contain exactly 64 hexadecimal characters.

The five optional hashed identity fields accept both uppercase and lowercase hex letters. A digest does not establish correct preimage normalization. Empty or nonhex supplied hashes fail their own local representation checks.

Rule: vendor.appsflyer-web-visit.http.email_hashed.invalid

A visit needs a valid page URL.

event_url is required on the visit route. It must use HTTP or HTTPS and stay within the documented character limit. The optional event URL on the event route has a separate presence contract.

Rule: vendor.appsflyer-web-visit.http.event_url_http

A nested user wrapper does not supply the required root identity.

The published endpoint table uses a top-level user_id object. A nested user.user_id value does not satisfy that field. The source inconsistency remains in the audit; unknown fields and custom parameters stay open.

Rule: vendor.appsflyer-web-visit.http.user_id.missing

What this pack matches

Hosts
events.appsflyer.com
Paths
Full path expression: ^/v2\.0/s2s/visits/app/web/[^/]*$
Vendor docs
support.appsflyer.com/hc/en-us/articles/45670116601617-Server-to-Server-S2S-API-for-Web-Performance-Measurement

Rules

Codes are stable. A finding in CI, MCP, or the playground lands on the same id.

Field Required What it checks Rule ids Source
app_id required Required dashboard unified_app_id. Website prefixes and registration truth are not inferred from examples. vendor.appsflyer-web-visit.param.app_id.missing
vendor.appsflyer-web-visit.param.app_id.empty
docs
method required The published operation uses POST. Complete HTTP capture contract. Native JSON type: string. vendor.appsflyer-web-visit.http.method.missing
vendor.appsflyer-web-visit.http.method.empty
vendor.appsflyer-web-visit.http.method.invalid
docs
content_type required All requests require application/json. Complete HTTP capture contract. Native JSON type: string. vendor.appsflyer-web-visit.http.content_type.missing
vendor.appsflyer-web-visit.http.content_type.empty
vendor.appsflyer-web-visit.http.content_type.invalid
docs
body_encoding required This operation carries a JSON entity. A locally unsupported decoder representation remains unvalidated. Complete HTTP capture contract. Applies when {"kind":"not","condition":{"kind":"value_in","param":"body_encoding","values":["unsupported"]}}. Native JSON type: string. vendor.appsflyer-web-visit.http.body_encoding.missing
vendor.appsflyer-web-visit.http.body_encoding.empty
vendor.appsflyer-web-visit.http.body_encoding.invalid
docs
headers.authorization required The published API requires an Authorization Bearer S2S token. Token validity and ownership remain external. Complete HTTP capture contract. Native JSON type: string. vendor.appsflyer-web-visit.http.headers.authorization.missing
vendor.appsflyer-web-visit.http.headers.authorization.empty
vendor.appsflyer-web-visit.http.headers.authorization.invalid
docs
url required The published endpoint uses HTTPS. Complete HTTP capture contract. Native JSON type: string. vendor.appsflyer-web-visit.http.url.missing
vendor.appsflyer-web-visit.http.url.empty
vendor.appsflyer-web-visit.http.url.invalid
docs
body required The endpoint body is a JSON object. Complete HTTP capture contract. Native JSON type: object. vendor.appsflyer-web-visit.http.body.missing
vendor.appsflyer-web-visit.http.body.invalid
docs
user_id required The published web table requires a top-level user_id object with at least one documented identifier. Complete HTTP capture contract. Capture scope: body. Native JSON type: object. vendor.appsflyer-web-visit.http.user_id.missing
vendor.appsflyer-web-visit.http.user_id.invalid
docs
event_url required The documented page URL uses HTTP or HTTPS and is at most 4096 characters. Complete HTTP capture contract. Capture scope: body. Presence diagnostic severity: error. Native JSON type: string. Maximum decoded characters: 4096. vendor.appsflyer-web-visit.http.event_url.missing
vendor.appsflyer-web-visit.http.event_url.empty
vendor.appsflyer-web-visit.http.event_url.invalid
docs
event_value optional Optional free-form event parameters remain an open object. Complete HTTP capture contract. Capture scope: body. Native JSON type: object. vendor.appsflyer-web-visit.http.event_value.invalid docs
event_value.custom_parameters optional The documented custom_parameters representation is a sub-object. Complete HTTP capture contract. Capture scope: body. Native JSON type: object. vendor.appsflyer-web-visit.http.event_value.custom_parameters.invalid docs
timestamp optional Optional Unix milliseconds use the published int64 type. App timezone and receipt time are external. Complete HTTP capture contract. Capture scope: body. Native JSON type: integer. Minimum numeric value: -9223372036854776000. Maximum numeric value: 9223372036854776000. vendor.appsflyer-web-visit.http.timestamp.invalid docs
ip optional Optional device IP accepts IPv4 or IPv6, up to 46 characters. Complete HTTP capture contract. Capture scope: body. Presence diagnostic severity: error. Native JSON type: string. Maximum decoded characters: 46. vendor.appsflyer-web-visit.http.ip.empty
vendor.appsflyer-web-visit.http.ip.invalid
docs
user_agent optional Optional browser user agent is at most 1024 characters. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. Maximum decoded characters: 1024. vendor.appsflyer-web-visit.http.user_agent.invalid docs
http_referrer optional The optional referrer is documented as a string. No extra length or scheme restriction is invented. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. vendor.appsflyer-web-visit.http.http_referrer.invalid docs
email_hashed optional The optional SHA256 representation must be exactly 64 hexadecimal characters. The preimage cannot be verified locally. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. Minimum decoded characters: 64. Maximum decoded characters: 64. vendor.appsflyer-web-visit.http.email_hashed.empty
vendor.appsflyer-web-visit.http.email_hashed.invalid
docs
phone_number_hashed optional The optional SHA256 representation must be exactly 64 hexadecimal characters. The preimage cannot be verified locally. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. Minimum decoded characters: 64. Maximum decoded characters: 64. vendor.appsflyer-web-visit.http.phone_number_hashed.empty
vendor.appsflyer-web-visit.http.phone_number_hashed.invalid
docs
phone_number_e164_hashed optional The optional SHA256 representation must be exactly 64 hexadecimal characters. The preimage cannot be verified locally. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. Minimum decoded characters: 64. Maximum decoded characters: 64. vendor.appsflyer-web-visit.http.phone_number_e164_hashed.empty
vendor.appsflyer-web-visit.http.phone_number_e164_hashed.invalid
docs
first_name_hashed optional The optional SHA256 representation must be exactly 64 hexadecimal characters. The preimage cannot be verified locally. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. Minimum decoded characters: 64. Maximum decoded characters: 64. vendor.appsflyer-web-visit.http.first_name_hashed.empty
vendor.appsflyer-web-visit.http.first_name_hashed.invalid
docs
last_name_hashed optional The optional SHA256 representation must be exactly 64 hexadecimal characters. The preimage cannot be verified locally. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. Minimum decoded characters: 64. Maximum decoded characters: 64. vendor.appsflyer-web-visit.http.last_name_hashed.empty
vendor.appsflyer-web-visit.http.last_name_hashed.invalid
docs
customer_dedup_id optional The visit deduplication ID is an optional string with no published size or format limit. Complete HTTP capture contract. Capture scope: body. Native JSON type: string. vendor.appsflyer-web-visit.http.customer_dedup_id.invalid docs
http.event_url_http required The documented page URL uses HTTP or HTTPS. Complete HTTP capture contract. Capture scope: body. vendor.appsflyer-web-visit.http.event_url_http docs
customer_user_id optional Customer identifier is 1 to 64 characters. Complete HTTP capture contract. Capture scope: body.user_id. Native JSON type: string. Minimum decoded characters: 1. Maximum decoded characters: 64. vendor.appsflyer-web-visit.http.customer_user_id.invalid docs
appsflyer_id optional AppsFlyer web identifier has at least one character. No upper limit is published. Complete HTTP capture contract. Capture scope: body.user_id. Native JSON type: string. Minimum decoded characters: 1. vendor.appsflyer-web-visit.http.appsflyer_id.invalid docs
http.user_id.identifier_required required Provide at least one identifier in the top-level user_id object. Complete HTTP capture contract. Capture scope: body.user_id. vendor.appsflyer-web-visit.http.user_id.identifier_required docs

Validate a payload

pixellint validate request @request.json --rulepack vendor/appsflyer-web-visit

Try this failing payload in the playground. The web visit omits event_url.

{"url":"https://events.appsflyer.com/v2.0/s2s/visits/app/web/website-example.com","method":"POST","headers":{"Content-Type":"application/json","Authorization":"Bearer LOCAL_EXAMPLE_TOKEN"},"body":"{\"user_id\":{\"customer_user_id\":\"local-example-user\"}}"}

cargo install pixellint · npm install pixellint