{"openapi":"3.1.0","info":{"title":"Rift API","description":"Deep links for humans and agents.\n\nRift creates smart, cross-platform deep links with structured context for AI agents. Each link carries per-platform destinations, metadata, and an optional `agent_context` that makes links machine-readable.\n\n## Authentication\n\nHumans sign in at `POST /v1/auth/signin` (magic-link email) and manage their account at `/account`. API callers use a secret key (`rl_live_…`) as a Bearer token in the Authorization header — mint one from `/account` after signing in. Client SDKs use publishable keys (`pk_live_`) for click tracking and attribution.\n\n## Quick start\n\n1. Sign in via `POST /v1/auth/signin` or the web `/signin` page — magic-link email\n2. Mint a key via `POST /v1/auth/secret-keys/issue` (session-authed)\n3. `POST /v1/links` — create your first link with the key\n4. `GET /r/{link_id}` — resolve it (redirect for browsers, JSON for agents)\n\n## Content negotiation\n\nThe resolve endpoint (`GET /r/{link_id}`) is content-negotiated. Browsers receive a redirect or landing page. Requests with `Accept: application/json` receive structured link data including `agent_context` and a `_rift_meta` trust envelope.","contact":{"name":"Rift","url":"https://riftl.ink"},"license":{"name":""},"version":"0.1.0"},"paths":{"/.well-known/apple-app-site-association":{"get":{"tags":["Apps"],"operationId":"serve_aasa","responses":{"200":{"description":"AASA JSON"},"404":{"description":"No iOS app configured"}}}},"/.well-known/assetlinks.json":{"get":{"tags":["Apps"],"operationId":"serve_assetlinks","responses":{"200":{"description":"Asset links JSON"},"404":{"description":"No Android app configured"}}}},"/health":{"get":{"tags":["System"],"operationId":"health","responses":{"200":{"description":"Server is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/r/{link_id}":{"get":{"tags":["Links"],"description":"Content-negotiated link resolution. Browsers receive a redirect or smart landing page. Requests with `Accept: application/json` receive structured link data including `agent_context` and a `_rift_meta` trust envelope.","operationId":"resolve_link","parameters":[{"name":"link_id","in":"path","description":"Link ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Structured link data with agent context and trust metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedLink"}}}},"302":{"description":"Redirect to destination"},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/affiliates":{"get":{"tags":["Affiliates"],"operationId":"list_affiliates","responses":{"200":{"description":"List of affiliates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAffiliatesResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Affiliates"],"operationId":"create_affiliate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAffiliateRequest"}}},"required":true},"responses":{"201":{"description":"Affiliate created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateDetail"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"partner_key already taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/affiliates/{affiliate_id}":{"get":{"tags":["Affiliates"],"operationId":"get_affiliate","parameters":[{"name":"affiliate_id","in":"path","description":"Affiliate id","required":true,"schema":{"$ref":"#/components/schemas/AffiliateId"}}],"responses":{"200":{"description":"Affiliate detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateDetail"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Affiliates"],"operationId":"delete_affiliate","parameters":[{"name":"affiliate_id","in":"path","description":"Affiliate id","required":true,"schema":{"$ref":"#/components/schemas/AffiliateId"}}],"responses":{"204":{"description":"Affiliate deleted"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]},"patch":{"tags":["Affiliates"],"operationId":"patch_affiliate","parameters":[{"name":"affiliate_id","in":"path","description":"Affiliate id","required":true,"schema":{"$ref":"#/components/schemas/AffiliateId"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAffiliateRequest"}}},"required":true},"responses":{"200":{"description":"Affiliate updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateDetail"}}}},"400":{"description":"Empty body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/affiliates/{affiliate_id}/credentials":{"get":{"tags":["Affiliates"],"operationId":"list_affiliate_credentials","parameters":[{"name":"affiliate_id","in":"path","description":"Affiliate id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of credentials (no raw secrets)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAffiliateCredentialsResponse"}}}},"404":{"description":"Affiliate not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Affiliates"],"operationId":"create_affiliate_credential","parameters":[{"name":"affiliate_id","in":"path","description":"Affiliate id","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Credential minted; api_key shown once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAffiliateCredentialResponse"}}}},"403":{"description":"Caller scope cannot mint credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Affiliate not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/affiliates/{affiliate_id}/credentials/{key_id}":{"delete":{"tags":["Affiliates"],"operationId":"revoke_affiliate_credential","parameters":[{"name":"affiliate_id","in":"path","description":"Affiliate id","required":true,"schema":{"type":"string"}},{"name":"key_id","in":"path","description":"Credential id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Credential revoked"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/analytics/stats":{"get":{"tags":["Analytics"],"operationId":"get_stats","parameters":[{"name":"link_ids","in":"query","description":"Comma-separated set of link_ids. One link = special case of one\nID. \"Campaign\" is whatever set the caller passes.","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start of date range, RFC 3339. Defaults to 30 days ago.","required":false,"schema":{"type":["string","null"]}},{"name":"to","in":"query","description":"End of date range, RFC 3339. Defaults to now.","required":false,"schema":{"type":["string","null"]}},{"name":"credit","in":"query","description":"Attribution model: `last_touch` (default — matches the\nmarketer's \"which campaign closed this user\"), `first_touch`,\nor `touched`. Unknown values fall back to `last_touch`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Branched funnel response across the link_ids set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelResult"}}}},"400":{"description":"Invalid query","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Database not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/apps":{"get":{"tags":["Apps"],"operationId":"list_apps","responses":{"200":{"description":"List of apps","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AppDetail"}}}}}},"security":[{"api_key":[]},{"x402":[]}]},"post":{"tags":["Apps"],"operationId":"create_app","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppRequest"}}},"required":true},"responses":{"201":{"description":"App registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppDetail"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/apps/{app_id}":{"delete":{"tags":["Apps"],"operationId":"delete_app","parameters":[{"name":"app_id","in":"path","description":"App ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"App deleted"},"404":{"description":"App not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/auth/callback":{"get":{"tags":["Sessions"],"operationId":"callback","parameters":[{"name":"token","in":"query","description":"Signin token from the magic-link email","required":true,"schema":{"type":"string"}},{"name":"next","in":"query","description":"Optional same-origin path to redirect to after sign-in","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"HTML interstitial — user clicks Continue to POST and consume the token","content":{"text/html":{}}}}},"post":{"tags":["Sessions"],"operationId":"callback_confirm","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/CallbackForm"}}},"required":true},"responses":{"303":{"description":"Token invalid or expired — redirects to `/signin?error=link_expired`"}}}},"/v1/auth/me":{"get":{"tags":["Sessions"],"operationId":"me","responses":{"200":{"description":"Resolved user + tenant for the active session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"401":{"description":"No active session (or session expired/revoked)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"session_cookie":[]}]}},"/v1/auth/oauth/{provider}/callback":{"get":{"tags":["Sessions"],"operationId":"callback","parameters":[{"name":"provider","in":"path","description":"`github` or `google`","required":true,"schema":{"type":"string"}},{"name":"code","in":"query","description":"Authorization code from the provider","required":false,"schema":{"type":"string"}},{"name":"state","in":"query","description":"Single-use state token we issued at `/start`","required":false,"schema":{"type":"string"}},{"name":"error","in":"query","description":"Set by the provider when the user cancels or denies","required":false,"schema":{"type":"string"}}],"responses":{"303":{"description":"Anything fails — redirects to `/signin?error=<code>`"}}}},"/v1/auth/oauth/{provider}/start":{"get":{"tags":["Sessions"],"operationId":"start","parameters":[{"name":"provider","in":"path","description":"`github` or `google`","required":true,"schema":{"type":"string"}},{"name":"next","in":"query","description":"Optional same-origin path on the marketing site to redirect to after sign-in. Defaults to `/account`.","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to the provider's authorize URL with state + PKCE challenge"},"404":{"description":"Unknown provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Provider not configured (missing client_id / client_secret env)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/auth/publishable-keys":{"get":{"tags":["Publishable Keys"],"operationId":"list_sdk_keys","responses":{"200":{"description":"List of SDK keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSdkKeysResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Publishable Keys"],"operationId":"create_sdk_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSdkKeyRequest"}}},"required":true},"responses":{"201":{"description":"SDK key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSdkKeyResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/auth/publishable-keys/{key_id}":{"delete":{"tags":["Publishable Keys"],"operationId":"revoke_sdk_key","parameters":[{"name":"key_id","in":"path","description":"SDK Key ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"SDK key revoked"},"404":{"description":"SDK key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/auth/secret-keys":{"get":{"tags":["Secret Keys"],"operationId":"list_secret_keys","responses":{"200":{"description":"List of secret keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretKeysResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Secret Keys"],"operationId":"request_create_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestCreateKeyRequest"}}},"required":true},"responses":{"200":{"description":"Confirmation code sent","content":{"application/json":{"schema":{}}}},"403":{"description":"User not authorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Key limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Request already pending","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/auth/secret-keys/confirm":{"post":{"tags":["Secret Keys"],"operationId":"confirm_create_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmCreateKeyRequest"}}},"required":true},"responses":{"201":{"description":"Key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"Invalid or expired code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/auth/secret-keys/issue":{"post":{"tags":["Secret Keys"],"operationId":"issue_secret_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueKeyRequest"}}},"required":true},"responses":{"201":{"description":"Key minted — full secret returned once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"401":{"description":"No active session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Per-tenant key limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Secret keys not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"session_cookie":[]}]}},"/v1/auth/secret-keys/{key_id}":{"delete":{"tags":["Secret Keys"],"operationId":"delete_secret_key","parameters":[{"name":"key_id","in":"path","description":"Secret Key ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Key deleted"},"404":{"description":"Key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Cannot delete last key or self","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/auth/signin":{"post":{"tags":["Sessions"],"operationId":"sign_in","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInRequest"}}},"required":true},"responses":{"200":{"description":"Always returned on validation success (prevents email enumeration)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignInResponse"}}}},"400":{"description":"Invalid email","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Per-IP rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Sessions not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/auth/signout":{"post":{"tags":["Sessions"],"operationId":"sign_out","responses":{"204":{"description":"Session revoked; `Set-Cookie` clears `session_token`"},"401":{"description":"No active session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"session_cookie":[]}]}},"/v1/auth/users":{"get":{"tags":["Team Members"],"operationId":"list_users","responses":{"200":{"description":"List of users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListUsersResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Team Members"],"operationId":"invite_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserRequest"}}},"required":true},"responses":{"201":{"description":"Invitation sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserResponse"}}}},"400":{"description":"Invalid email","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"User already on this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/auth/users/{user_id}":{"delete":{"tags":["Team Members"],"operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"User removed"},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Cannot remove last verified user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/auth/verify":{"get":{"tags":["Team"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Verification token from a team-invite email","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"HTML interstitial — invitee clicks Accept to POST and consume the token","content":{"text/html":{}}}}},"post":{"tags":["Team"],"operationId":"verify_email_confirm","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/VerifyForm"}}},"required":true},"responses":{"303":{"description":"Token invalid or expired — redirects to `${marketing_url}/signin?error=invite_invalid`"}}}},"/v1/billing/cancel":{"post":{"tags":["Billing"],"operationId":"cancel_subscription","responses":{"200":{"description":"Cancellation scheduled for period end"},"400":{"description":"Tenant has no cancellable subscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Stripe not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/billing/status":{"get":{"tags":["Billing"],"operationId":"get_billing_status","responses":{"200":{"description":"Current billing state for the authenticated tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingStatusResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Billing service not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/billing/stripe/checkout":{"post":{"tags":["Billing"],"operationId":"create_stripe_checkout","parameters":[{"name":"tier","in":"query","description":"Target tier. One of: pro, business, scale.","required":true,"schema":{"type":"string"},"example":"pro"}],"responses":{"200":{"description":"Stripe Checkout session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionResponse"}}}},"400":{"description":"Invalid tier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Stripe not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/billing/stripe/portal":{"post":{"tags":["Billing"],"operationId":"create_stripe_portal","responses":{"200":{"description":"Stripe Billing Portal session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalSessionResponse"}}}},"400":{"description":"Tenant has no Stripe customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Stripe not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/domains":{"get":{"tags":["Domains"],"operationId":"list_domains","responses":{"200":{"description":"List of domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DomainDetail"}}}}}},"security":[{"api_key":[]},{"x402":[]}]},"post":{"tags":["Domains"],"operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainResponse"}}}},"400":{"description":"Invalid domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Domain already registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/domains/{domain}":{"delete":{"tags":["Domains"],"operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain to delete","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted"},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/domains/{domain}/verify":{"post":{"tags":["Domains"],"operationId":"verify_domain","parameters":[{"name":"domain","in":"path","description":"Domain to verify","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyDomainResponse"}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/lifecycle/attribute":{"post":{"tags":["Lifecycle"],"operationId":"lifecycle_attribute","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributeRequest"}}},"required":true},"responses":{"200":{"description":"Attribution event recorded"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/lifecycle/click":{"post":{"tags":["Lifecycle"],"operationId":"lifecycle_click","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClickRequest"}}},"required":true},"responses":{"200":{"description":"Click recorded, link data returned"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/lifecycle/convert":{"post":{"tags":["Lifecycle"],"operationId":"sdk_track_conversion","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SdkConversionRequest"}}},"required":true},"responses":{"200":{"description":"Event processed"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/lifecycle/identify":{"put":{"tags":["Lifecycle"],"operationId":"lifecycle_identify","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdentifyRequest"}}},"required":true},"responses":{"200":{"description":"Install bound to user"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Install already bound to a different user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/v1/links":{"get":{"tags":["Links"],"operationId":"list_links","parameters":[{"name":"limit","in":"query","description":"Maximum number of links to return (1-100, default 50).","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cursor","in":"query","description":"Cursor for pagination — pass `next_cursor` from the previous response.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of links","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListLinksResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]},"post":{"tags":["Links"],"operationId":"create_link","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkRequest"}}},"required":true},"responses":{"201":{"description":"Link created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Link ID already taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/links/bulk":{"post":{"tags":["Links"],"operationId":"create_links_bulk","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCreateLinksRequest"}}},"required":true},"responses":{"201":{"description":"All links created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkCreateLinksResponse"}}}},"400":{"description":"Invalid batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Quota exceeded"}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/links/{link_id}":{"get":{"tags":["Links"],"operationId":"get_link","parameters":[{"name":"link_id","in":"path","description":"Link ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Link details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkDetail"}}}},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]},"put":{"tags":["Links"],"operationId":"update_link","parameters":[{"name":"link_id","in":"path","description":"Link ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLinkRequest"}}},"required":true},"responses":{"200":{"description":"Link updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkDetail"}}}},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]},"delete":{"tags":["Links"],"operationId":"delete_link","parameters":[{"name":"link_id","in":"path","description":"Link ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Link deleted"},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/links/{link_id}/qr.{format}":{"get":{"tags":["Links"],"operationId":"get_link_qr","parameters":[{"name":"link_id","in":"path","description":"Link ID","required":true,"schema":{"type":"string"}},{"name":"format","in":"path","description":"Output format: `png` or `svg`","required":true,"schema":{"type":"string"},"example":"png"},{"name":"logo","in":"query","description":"Logo image URL to center in the QR code.","required":false,"schema":{"type":["string","null"]}},{"name":"size","in":"query","description":"Output size in pixels. Defaults to 600.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0},"example":600},{"name":"level","in":"query","description":"QR error correction level. One of L, M, Q, H. Defaults to L (or H when a logo is set).","required":false,"schema":{"type":["string","null"]},"example":"H"},{"name":"fgColor","in":"query","description":"Foreground color hex value applied to dots, eye frames, and eye pupils when their\nper-component color is not set. Defaults to #000000.","required":false,"schema":{"type":["string","null"]},"example":"#111827"},{"name":"bgColor","in":"query","description":"Background color hex value. Defaults to #FFFFFF.","required":false,"schema":{"type":["string","null"]},"example":"#FFFFFF"},{"name":"hideLogo","in":"query","description":"Ignore the logo URL when true.","required":false,"schema":{"type":"boolean"}},{"name":"margin","in":"query","description":"Margin around the QR code in modules. Defaults to 2.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0},"example":2},{"name":"includeMargin","in":"query","description":"Deprecated compatibility flag. If false and margin is absent, margin becomes 0.","required":false,"schema":{"type":["boolean","null"]}},{"name":"dotType","in":"query","description":"Shape of the inner dots. One of `square`, `dots`, `rounded`, `classy`,\n`classy-rounded`, `extra-rounded`. Defaults to `rounded`.","required":false,"schema":{"type":["string","null"]},"example":"rounded"},{"name":"cornerSquareType","in":"query","description":"Shape of the three large positioning \"eye\" frames. One of `square`, `dot`,\n`extra-rounded`. Defaults to `extra-rounded`.","required":false,"schema":{"type":["string","null"]},"example":"extra-rounded"},{"name":"cornerDotType","in":"query","description":"Shape of the pupil inside each eye frame. One of `dot`, `square`. Defaults to `dot`.","required":false,"schema":{"type":["string","null"]},"example":"dot"},{"name":"shape","in":"query","description":"Overall canvas shape. One of `square`, `circle`. Defaults to `square`.","required":false,"schema":{"type":["string","null"]},"example":"square"},{"name":"dotColor","in":"query","description":"Override color for the inner dots only. Defaults to `fgColor`.","required":false,"schema":{"type":["string","null"]},"example":"#0d9488"},{"name":"cornerSquareColor","in":"query","description":"Override color for the eye frames only. Defaults to `fgColor`.","required":false,"schema":{"type":["string","null"]},"example":"#111827"},{"name":"cornerDotColor","in":"query","description":"Override color for the eye pupils only. Defaults to `fgColor`.","required":false,"schema":{"type":["string","null"]},"example":"#111827"}],"responses":{"200":{"description":"SVG QR code","content":{"image/svg+xml":{}}},"400":{"description":"Invalid QR format or options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/sources":{"get":{"tags":["Sources"],"operationId":"list_sources","responses":{"200":{"description":"List of sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSourcesResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]},"post":{"tags":["Sources"],"operationId":"create_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSourceRequest"}}},"required":true},"responses":{"201":{"description":"Source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Source name already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/sources/{id}":{"get":{"tags":["Sources"],"operationId":"get_source","parameters":[{"name":"id","in":"path","description":"Source ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceDetail"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]},"delete":{"tags":["Sources"],"operationId":"delete_source","parameters":[{"name":"id","in":"path","description":"Source ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"operationId":"list_webhooks","responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWebhooksResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]},"post":{"tags":["Webhooks"],"operationId":"create_webhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/v1/webhooks/{webhook_id}":{"delete":{"tags":["Webhooks"],"operationId":"delete_webhook","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Webhook deleted"},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]},"patch":{"tags":["Webhooks"],"operationId":"patch_webhook","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDetail"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"api_key":[]},{"x402":[]}]}},"/{link_id}":{"get":{"tags":["Links"],"operationId":"resolve_link_custom","parameters":[{"name":"link_id","in":"path","description":"Link ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Link metadata (JSON)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedLink"}}}},"302":{"description":"Redirect to destination"},"404":{"description":"Link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"AffiliateCredentialDetail":{"type":"object","required":["id","key_prefix","created_at"],"properties":{"created_at":{"type":"string","example":"2026-04-25T10:30:00Z"},"id":{"type":"string","example":"skid_665a1b2c3d4e5f6a7b8c9d0e"},"key_prefix":{"type":"string","example":"rl_live_4f2c3a8b9d..."}}},"AffiliateDetail":{"type":"object","required":["id","name","partner_key","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"id":{"$ref":"#/components/schemas/AffiliateId"},"name":{"type":"string","example":"Bcom"},"partner_key":{"type":"string","example":"bcom"},"status":{"$ref":"#/components/schemas/AffiliateStatus"},"updated_at":{"type":"string","example":"2025-06-15T10:30:00Z"}}},"AffiliateId":{"type":"string","description":"Prefixed public identifier (prefix `aff_`, 24-char lowercase ObjectId hex body).","examples":["aff_000000000000000000000000"],"pattern":"^aff_[0-9a-f]{24}$"},"AffiliateStatus":{"type":"string","enum":["active","disabled"]},"AgentContext":{"type":"object","description":"Structured context for AI agents resolving this link.","properties":{"action":{"type":["string","null"],"description":"The link's intent. Must be one of: purchase, subscribe, signup, download, read, book, open.","example":"book"},"cta":{"type":["string","null"],"description":"Short call-to-action shown to the end user (max 120 characters).","example":"Reserve a table for tonight"},"description":{"type":["string","null"],"description":"Freeform context about the offer, product, or content for AI agents (max 500 characters).","example":"Opens the TableFour app to book a reservation at the selected restaurant"}}},"AppDetail":{"type":"object","required":["id","platform","created_at"],"properties":{"app_name":{"type":["string","null"],"example":"TableFour"},"bundle_id":{"type":["string","null"],"example":"com.tablefour.app"},"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"icon_url":{"type":["string","null"],"example":"https://cdn.tablefour.com/icon-512.png"},"id":{"$ref":"#/components/schemas/AppId"},"package_name":{"type":["string","null"],"example":"com.tablefour.app"},"platform":{"type":"string","example":"ios"},"sha256_fingerprints":{"type":["array","null"],"items":{"type":"string"}},"team_id":{"type":["string","null"],"example":"A1B2C3D4E5"},"theme_color":{"type":["string","null"],"example":"#FF6B35"}}},"AppId":{"type":"string","description":"Prefixed public identifier (prefix `app_`, 24-char lowercase ObjectId hex body).","examples":["app_000000000000000000000000"],"pattern":"^app_[0-9a-f]{24}$"},"AttributeContext":{"type":"object","description":"Device / app context captured by the SDK. Mirror of\n[`crate::services::install_events::models::InstallContext`] at the\nAPI boundary — kept as a separate type so OpenAPI schemas don't leak\ninternal storage types.","properties":{"app_version":{"type":["string","null"],"example":"2.4.1"},"device_manufacturer":{"type":["string","null"],"example":"Apple"},"device_model":{"type":["string","null"],"example":"iPhone15,4"},"locale":{"type":["string","null"],"example":"en_US"},"os":{"type":["string","null"],"example":"iOS"},"os_version":{"type":["string","null"],"example":"17.4.1"},"platform":{"type":["string","null"],"example":"ios"},"region":{"type":["string","null"],"example":"US"},"timezone":{"type":["string","null"],"example":"America/Los_Angeles"}}},"AttributeRequest":{"type":"object","required":["link_id","install_id","app_version"],"properties":{"app_version":{"type":"string","example":"2.4.1"},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AttributeContext","description":"Optional device + app context captured by the SDK from public OS\nAPIs (no permissions required). Used server-side to enrich\n`install.created` events and to distinguish `install.reinstalled`\nfrom `install.new_device` on identify. Absent on older SDK\nversions that pre-date the context-capture release."}]},"install_id":{"type":"string","example":"d4f7a1b2-3c8e-4f9a-b5d6-7e8f9a0b1c2d"},"link_id":{"type":"string","example":"summer-menu-2025"}}},"AttributeResponse":{"type":"object","description":"Response from `POST /v1/lifecycle/attribute`. Today: `{success}` only.\nForward room: `event_id` (stable id customers can dedup against),\n`is_first_touch` (signal whether `installs` row was newly inserted).","required":["success"],"properties":{"success":{"type":"boolean","example":true}}},"BatchItemError":{"type":"object","description":"Per-row failure surfaced when a batch is rejected without inserting\nanything. The full list is returned in one response so the caller can fix\nevery problem in one pass and retry.","required":["index","code","message"],"properties":{"code":{"type":"string","example":"link_id_taken"},"custom_id":{"type":["string","null"],"example":"promo-2"},"index":{"type":"integer","example":4,"minimum":0},"message":{"type":"string","example":"'promo-2' is already taken"}}},"BillingMethod":{"type":"string","enum":["free","stripe","x402"]},"BillingStatusResponse":{"type":"object","description":"Slim JSON shape for the status endpoint. Rendered from `BillingStatus` so\nthe external contract stays stable if we add internal fields later.","required":["plan_tier","effective_tier","comp_active","billing_method","status","limits"],"properties":{"billing_method":{"$ref":"#/components/schemas/BillingMethod"},"comp_active":{"type":"boolean"},"current_period_end":{"type":["integer","null"],"format":"int64"},"effective_tier":{"$ref":"#/components/schemas/PlanTier"},"limits":{"$ref":"#/components/schemas/LimitsView"},"plan_tier":{"$ref":"#/components/schemas/PlanTier"},"status":{"$ref":"#/components/schemas/SubscriptionStatus"}}},"BulkCreateLinksRequest":{"type":"object","description":"Bulk create request. Exactly one of `custom_ids` or `count` must be set.\n`custom_ids` mode: caller-supplied vanity slugs (each 3-64 chars,\nalphanumeric + hyphens). `count` mode: server generates N random 8-char\nuppercase IDs.","required":["template"],"properties":{"count":{"type":["integer","null"],"format":"int32","description":"Number of links to generate with auto-assigned 8-char IDs.\nMutually exclusive with `custom_ids`. Max 100 per batch.","example":50,"minimum":0},"custom_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Caller-supplied vanity slugs (3-64 chars, alphanumeric + hyphens).\nMutually exclusive with `count`."},"template":{"$ref":"#/components/schemas/BulkLinkTemplate","description":"Shared destinations and metadata applied to every link in the batch."}}},"BulkCreateLinksResponse":{"type":"object","required":["links"],"properties":{"links":{"type":"array","items":{"$ref":"#/components/schemas/BulkLinkResult"},"description":"Every link successfully created by the batch, in input order."}}},"BulkLinkResult":{"type":"object","required":["link_id","url"],"properties":{"link_id":{"type":"string","description":"The link's vanity slug or auto-generated ID — the path segment after the domain.","example":"partner-acme"},"url":{"type":"string","description":"The fully-qualified link URL ready to share.","example":"https://go.acme.com/partner-acme"}}},"BulkLinkTemplate":{"type":"object","description":"Template applied to every link in a bulk-create request. Same fields as\n`CreateLinkRequest` minus `custom_id` (the bulk endpoint generates or\naccepts a list of IDs separately) and minus `affiliate_id` (the caller's\nscope governs attribution for the whole batch).","properties":{"affiliate_id":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AffiliateId","description":"Affiliate this whole batch should be attributed to. Optional for full-scope\ncallers; ignored / overridden for affiliate-scoped callers."}]},"agent_context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentContext","description":"Structured context for AI agents applied to every link in the batch."}]},"android_deep_link":{"type":["string","null"],"description":"Android deep link URI applied to every link in the batch.","example":"tablefour://restaurant/782/reserve"},"android_store_url":{"type":["string","null"],"description":"Play Store link for Android applied to every link in the batch.","example":"https://play.google.com/store/apps/details?id=com.tablefour.app"},"ios_deep_link":{"type":["string","null"],"description":"iOS deep link URI applied to every link in the batch (e.g. \"myapp://product/123\").","example":"tablefour://restaurant/782/reserve"},"ios_store_url":{"type":["string","null"],"description":"App Store link for iOS applied to every link in the batch.","example":"https://apps.apple.com/app/tablefour/id1234567890"},"metadata":{"description":"Arbitrary key-value metadata copied onto every link in the batch."},"social_preview":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SocialPreview","description":"Open Graph / Twitter preview data applied to every link in the batch."}]},"web_url":{"type":["string","null"],"description":"Web fallback URL applied to every link (desktop / unknown platforms).","example":"https://tablefour.com/restaurant/782"}}},"CallbackForm":{"type":"object","description":"Form body for `POST /v1/auth/callback` — submitted by the interstitial\nHTML page that `GET /v1/auth/callback` renders. The GET handler doesn't\nconsume the token (email link scanners like Avanan, Defender Safe Links,\nand ProofPoint pre-fetch links and would burn it before the user clicks);\nonly this POST does. Scanners follow GETs but don't submit forms.","required":["token"],"properties":{"next":{"type":["string","null"]},"token":{"type":"string"}}},"CheckoutSessionResponse":{"type":"object","required":["checkout_url"],"properties":{"checkout_url":{"type":"string"}}},"ClickRequest":{"type":"object","required":["link_id"],"properties":{"link_id":{"type":"string","example":"summer-menu-2025"}}},"ConfirmCreateKeyRequest":{"type":"object","required":["email","token"],"properties":{"email":{"type":"string","description":"Email of the user who received the confirmation code.","example":"alice@example.com"},"token":{"type":"string","description":"The 6-character confirmation code from the email.","example":"ABC123"}}},"CreateAffiliateCredentialResponse":{"type":"object","description":"Returned ONCE on successful credential mint. The advertiser is responsible\nfor handing `api_key` to the partner out-of-band. Rift will never reveal\nit again — list endpoints only return the prefix.","required":["id","affiliate_id","api_key","key_prefix","created_at"],"properties":{"affiliate_id":{"$ref":"#/components/schemas/AffiliateId","description":"Affiliate this credential is scoped to."},"api_key":{"type":"string","description":"Plaintext `rl_live_…` key. Shown only once.","example":"rl_live_4f2c3a8b9d0e1f2a3b4c5d6e7f8a9b0c"},"created_at":{"type":"string","example":"2026-04-25T10:30:00Z"},"id":{"type":"string","description":"Credential id (the secret key id).","example":"skid_665a1b2c3d4e5f6a7b8c9d0e"},"key_prefix":{"type":"string","description":"First-18-chars-of-key prefix shown in subsequent list calls.","example":"rl_live_4f2c3a8b9d..."}}},"CreateAffiliateRequest":{"type":"object","description":"Register a partner that will drive traffic to your app. The `partner_key`\nmust be a unique lowercase slug per tenant — used to route postbacks\n(when the dispatcher ships) and identify the partner in event metadata.","required":["name","partner_key"],"properties":{"name":{"type":"string","description":"Human-readable partner name.","example":"Bcom"},"partner_key":{"type":"string","description":"Unique slug per tenant. Lowercase letters, digits, and `-`. 2–32 chars.","example":"bcom"}}},"CreateAppRequest":{"type":"object","required":["platform"],"properties":{"app_name":{"type":["string","null"],"description":"App display name.","example":"TableFour"},"bundle_id":{"type":["string","null"],"description":"iOS bundle ID.","example":"com.tablefour.app"},"icon_url":{"type":["string","null"],"description":"App icon URL.","example":"https://cdn.tablefour.com/icon-512.png"},"package_name":{"type":["string","null"],"description":"Android package name.","example":"com.tablefour.app"},"platform":{"type":"string","description":"\"ios\" or \"android\".","example":"ios"},"sha256_fingerprints":{"type":["array","null"],"items":{"type":"string"},"description":"Android signing certificate SHA-256 fingerprints."},"team_id":{"type":["string","null"],"description":"Apple Team ID.","example":"A1B2C3D4E5"},"theme_color":{"type":["string","null"],"description":"Theme color (hex).","example":"#FF6B35"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","description":"Custom domain to register (e.g. \"go.tablefour.com\").","example":"go.tablefour.com"},"role":{"type":["string","null"],"description":"Domain role: \"primary\" (default) or \"alternate\" (Universal Link trampoline).","example":"primary"}}},"CreateDomainResponse":{"type":"object","required":["domain","verified","verification_token","txt_record","cname_target"],"properties":{"cname_target":{"type":"string","description":"CNAME target for routing traffic.","example":"cname.riftl.ink"},"domain":{"type":"string","example":"go.tablefour.com"},"txt_record":{"type":"string","description":"TXT record name to create for verification.","example":"_relay-challenge.go.tablefour.com"},"verification_token":{"type":"string","example":"relay-verify-a1b2c3d4e5f6"},"verified":{"type":"boolean","example":false}}},"CreateKeyResponse":{"type":"object","required":["id","key","key_prefix","created_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"id":{"type":"string","example":"skid_665a1b2c3d4e5f6a7b8c9d0e"},"key":{"type":"string","description":"The full secret key. Shown only once at creation time.","example":"rl_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2"},"key_prefix":{"type":"string","example":"rl_live_a1b2c3d4..."}}},"CreateLinkRequest":{"type":"object","properties":{"affiliate_id":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AffiliateId","description":"Affiliate this link should be attributed to. Optional for full-scope\ncallers (advertiser keys); ignored / overridden for affiliate-scoped\ncallers — server pins to the credential's affiliate. Mismatched values\nfrom a scoped caller return `affiliate_scope_mismatch`."}]},"agent_context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentContext","description":"Structured context for AI agents. When set, agents resolving this link receive action, CTA, and description metadata alongside the destinations."}]},"android_deep_link":{"type":["string","null"],"description":"Android deep link URI.","example":"tablefour://restaurant/782/reserve"},"android_store_url":{"type":["string","null"],"description":"Play Store link for Android.","example":"https://play.google.com/store/apps/details?id=com.tablefour.app"},"custom_id":{"type":["string","null"],"description":"Optional vanity slug (3-64 chars, alphanumeric + hyphens).","example":"summer-menu-2025"},"ios_deep_link":{"type":["string","null"],"description":"iOS deep link URI (e.g. \"myapp://product/123\").","example":"tablefour://restaurant/782/reserve"},"ios_store_url":{"type":["string","null"],"description":"App Store link for iOS.","example":"https://apps.apple.com/app/tablefour/id1234567890"},"metadata":{"description":"Arbitrary key-value metadata."},"social_preview":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SocialPreview","description":"Public Open Graph/Twitter preview data rendered on Rift landing pages."}]},"web_url":{"type":["string","null"],"description":"Web fallback URL for desktop/unknown platforms.","example":"https://tablefour.com/restaurant/782"}}},"CreateLinkResponse":{"type":"object","required":["link_id","url"],"properties":{"expires_at":{"type":["string","null"],"description":"When this link expires (RFC 3339). Null for permanent links. Links without a verified custom domain expire after 30 days.","example":"2025-07-15T10:30:00Z"},"link_id":{"type":"string","description":"The link's vanity slug or auto-generated ID — the path segment after the domain.","example":"summer-menu-2025"},"url":{"type":"string","description":"The fully-qualified link URL ready to share.","example":"https://riftl.ink/summer-menu-2025"}}},"CreateSdkKeyRequest":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain to bind this SDK key to (must be verified and owned by tenant).","example":"go.tablefour.com"}}},"CreateSdkKeyResponse":{"type":"object","required":["id","key","domain","created_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"domain":{"type":"string","example":"go.tablefour.com"},"id":{"type":"string","example":"pkid_665a1b2c3d4e5f6a7b8c9d0e"},"key":{"type":"string","description":"The full SDK key. Shown only once at creation time.","example":"pk_live_a1b2c3d4e5f6g7h8i9j0"}}},"CreateSourceRequest":{"type":"object","required":["name","source_type"],"properties":{"name":{"type":"string","description":"Human-readable name. Unique per tenant.","example":"backend-deposits"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type. v1 supports `custom` only."}}},"CreateSourceResponse":{"type":"object","required":["id","name","source_type","webhook_url","created_at"],"properties":{"created_at":{"type":"string","example":"2026-04-10T12:00:00Z"},"id":{"$ref":"#/components/schemas/SourceId"},"name":{"type":"string","example":"backend-deposits"},"source_type":{"$ref":"#/components/schemas/SourceType"},"webhook_url":{"type":"string","description":"The public webhook URL for this source. Include this in your backend or\nintegration webhook config. The URL token is unguessable; the URL itself\nis the auth. Rotate by deleting + recreating the source.","example":"https://api.riftl.ink/w/a1b2c3d4e5f6..."}}},"CreateWebhookRequest":{"type":"object","description":"Register a URL to receive real-time HMAC-signed POST requests when clicks or attributions occur.\nThe signing secret is returned once at creation time — save it to verify webhook signatures.\nPayloads are JSON with `event`, `timestamp`, and `data` fields. Maximum 2 webhooks per tenant.","required":["url","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEventType"}},"filters":{"$ref":"#/components/schemas/WebhookFilters","description":"Optional delivery filters. Omit (or send `{}`) to receive every\nsubscribed event. Currently supports `affiliate_id` to restrict\nconversions to one affiliate's links."},"url":{"type":"string","description":"HTTPS URL to receive webhook POST requests.","example":"https://api.tablefour.com/webhooks/relay"}}},"CreateWebhookResponse":{"type":"object","required":["id","url","events","secret","created_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEventType"}},"filters":{"$ref":"#/components/schemas/WebhookFilters","description":"Delivery filters applied to this webhook. Omitted when empty."},"id":{"$ref":"#/components/schemas/WebhookId"},"secret":{"type":"string","description":"HMAC-SHA256 signing secret. Use this to verify webhook payloads. Shown only once at creation time.","example":"whsec_k7J2mN9pQ4rT1vX8yB3cF6gH0"},"url":{"type":"string","example":"https://api.tablefour.com/webhooks/relay"}}},"DomainDetail":{"type":"object","required":["domain","verified","role","created_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"domain":{"type":"string","example":"go.tablefour.com"},"role":{"type":"string","example":"primary"},"verified":{"type":"boolean","example":true}}},"ErrorResponse":{"type":"object","description":"Error response returned on failures.","required":["error","code"],"properties":{"code":{"type":"string","description":"Machine-readable error code.","example":"not_found"},"error":{"type":"string","description":"Human-readable error message.","example":"Not found: link with id 'abc123' does not exist"}}},"Funnel":{"type":"object","required":["clicks","new_users","returning_users","conversions"],"properties":{"clicks":{"type":"integer","format":"int64","example":4892,"minimum":0},"conversions":{"type":"object","description":"Conversions across both new and returning users, keyed by\nconversion type (e.g. \"signup\", \"purchase\").","additionalProperties":{"type":"integer","format":"int64","minimum":0},"propertyNames":{"type":"string"}},"new_users":{"$ref":"#/components/schemas/NewUsers"},"returning_users":{"$ref":"#/components/schemas/ReturningUsers"}}},"FunnelResult":{"type":"object","description":"Funnel response — one number per leaf, four top-level stages.","required":["from","to","link_ids","credit","funnel"],"properties":{"credit":{"type":"string","description":"Attribution model the counts were computed under.","example":"last_touch"},"from":{"type":"string","description":"ISO 8601.","example":"2026-04-01T00:00:00Z"},"funnel":{"$ref":"#/components/schemas/Funnel"},"link_ids":{"type":"array","items":{"type":"string"}},"to":{"type":"string","example":"2026-05-21T00:00:00Z"}}},"HealthResponse":{"type":"object","required":["status"],"properties":{"status":{"type":"string","example":"ok"}}},"IdentifyRequest":{"type":"object","required":["install_id","user_id"],"properties":{"install_id":{"type":"string","example":"d4f7a1b2-3c8e-4f9a-b5d6-7e8f9a0b1c2d"},"user_id":{"type":"string","example":"user_12345"}}},"IdentifyResponse":{"type":"object","description":"Response from `PUT /v1/lifecycle/identify`. Today: `{success}` only.\nForward room: `prior_attributions` (anonymous events just linked to\nthis user_id), `bound_at` (server-side timestamp of the binding).","required":["success"],"properties":{"success":{"type":"boolean","example":true}}},"InviteUserRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","description":"Email address of the user to invite.","example":"alice@example.com"}}},"InviteUserResponse":{"type":"object","required":["id","email","status"],"properties":{"email":{"type":"string","example":"alice@example.com"},"id":{"$ref":"#/components/schemas/UserId"},"status":{"type":"string","example":"verification_sent"}}},"IssueKeyRequest":{"type":"object","description":"`POST /v1/auth/secret-keys/issue` request body.\n\nEmpty in Phase 1 — the session middleware already proves the caller's\nidentity. Phase 3 will add an optional `name` field for friendly key labels;\nkeeping the body a struct (vs. `()`) makes that addition non-breaking."},"LimitsView":{"type":"object","required":["analytics_retention"],"properties":{"analytics_retention":{"type":"string"},"max_domains":{"type":["integer","null"],"format":"int64","minimum":0},"max_events_per_month":{"type":["integer","null"],"format":"int64","minimum":0},"max_links":{"type":["integer","null"],"format":"int64","minimum":0},"max_team_members":{"type":["integer","null"],"format":"int64","minimum":0},"max_webhooks":{"type":["integer","null"],"format":"int64","minimum":0}}},"LinkDetail":{"type":"object","required":["link_id","url","created_at"],"properties":{"affiliate_id":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AffiliateId","description":"Affiliate this link is attributed to. None for unattributed links."}]},"agent_context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentContext","description":"Structured context for AI agents resolving this link."}]},"android_deep_link":{"type":["string","null"],"description":"Android deep link URI this link redirects to on Android devices with the app installed.","example":"tablefour://restaurant/782/reserve"},"android_store_url":{"type":["string","null"],"description":"Play Store URL for Android users without the app installed.","example":"https://play.google.com/store/apps/details?id=com.tablefour.app"},"created_at":{"type":"string","description":"When this link was created (RFC 3339).","example":"2025-06-15T10:30:00Z"},"ios_deep_link":{"type":["string","null"],"description":"iOS deep link URI this link redirects to on iOS devices with the app installed.","example":"tablefour://restaurant/782/reserve"},"ios_store_url":{"type":["string","null"],"description":"App Store URL for iOS users without the app installed.","example":"https://apps.apple.com/app/tablefour/id1234567890"},"link_id":{"type":"string","description":"The link's vanity slug or auto-generated ID — the path segment after the domain.","example":"summer-menu-2025"},"social_preview":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SocialPreview","description":"Open Graph / Twitter preview metadata rendered on Rift landing pages."}]},"url":{"type":"string","description":"The fully-qualified link URL ready to share.","example":"https://riftl.ink/summer-menu-2025"},"web_url":{"type":["string","null"],"description":"Web fallback URL for desktop / unknown platforms.","example":"https://tablefour.com/restaurant/782"}}},"ListAffiliateCredentialsResponse":{"type":"object","required":["credentials"],"properties":{"credentials":{"type":"array","items":{"$ref":"#/components/schemas/AffiliateCredentialDetail"}}}},"ListAffiliatesResponse":{"type":"object","required":["affiliates"],"properties":{"affiliates":{"type":"array","items":{"$ref":"#/components/schemas/AffiliateDetail"}}}},"ListLinksResponse":{"type":"object","required":["links"],"properties":{"links":{"type":"array","items":{"$ref":"#/components/schemas/LinkDetail"},"description":"The current page of links, most recent first."},"next_cursor":{"type":["string","null"],"description":"Cursor for the next page. Null if no more results.","example":"lnk_665a1b2c3d4e5f6a7b8c9d0e"}}},"ListSdkKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/SdkKeyDetail"}}}},"ListSecretKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/SecretKeyDetail"}}}},"ListSourcesResponse":{"type":"object","required":["sources"],"properties":{"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceDetail"}}}},"ListUsersResponse":{"type":"object","required":["users"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/UserDetail"}}}},"ListWebhooksResponse":{"type":"object","required":["webhooks"],"properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDetail"}}}},"MeResponse":{"type":"object","required":["user","tenant"],"properties":{"tenant":{"$ref":"#/components/schemas/TenantSummary"},"user":{"$ref":"#/components/schemas/UserSummary"}}},"NewUsers":{"type":"object","required":["installed","identified"],"properties":{"identified":{"type":"integer","format":"int64","description":"Of those installs, how many became identified users.","example":198,"minimum":0},"installed":{"type":"integer","format":"int64","description":"First-time install_ids attributed to these links.","example":240,"minimum":0}}},"PlanTier":{"type":"string","enum":["free","pro","business","scale"]},"PortalSessionResponse":{"type":"object","required":["portal_url"],"properties":{"portal_url":{"type":"string"}}},"RequestCreateKeyRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","description":"Email of a verified user on this tenant who will receive the confirmation code.","example":"alice@example.com"}}},"ResolvedLink":{"type":"object","description":"Response returned when resolving a link with `Accept: application/json`.\nIncludes destinations, metadata, agent context, and a `_rift_meta` trust envelope.","required":["link_id","_rift_meta"],"properties":{"_rift_meta":{"$ref":"#/components/schemas/RiftMeta","description":"Trust envelope with provenance and status information for agents."},"agent_context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentContext"}]},"android_deep_link":{"type":["string","null"],"example":"tablefour://restaurant/782/reserve"},"android_store_url":{"type":["string","null"],"example":"https://play.google.com/store/apps/details?id=com.tablefour.app"},"ios_deep_link":{"type":["string","null"],"example":"tablefour://restaurant/782/reserve"},"ios_store_url":{"type":["string","null"],"example":"https://apps.apple.com/app/tablefour/id1234567890"},"link_id":{"type":"string","example":"summer-menu-2025"},"metadata":{},"social_preview":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SocialPreview"}]},"web_url":{"type":["string","null"],"example":"https://tablefour.com/restaurant/782"}}},"ReturningUsers":{"type":"object","required":["reinstalled","new_device","engaged"],"properties":{"engaged":{"type":"integer","format":"int64","description":"Known install touched the link again (active re-engagement).","example":1200,"minimum":0},"new_device":{"type":"integer","format":"int64","description":"Known user appeared on a new install_id with a DIFFERENT device\nmodel (added another phone / tablet).","example":20,"minimum":0},"reinstalled":{"type":"integer","format":"int64","description":"Known user appeared on a new install_id with the SAME device\nmodel (uninstall + reinstall — Android-detectable).","example":30,"minimum":0}}},"RiftMeta":{"type":"object","description":"Trust envelope included in every resolved link response.","required":["context","source","status","tenant_verified"],"properties":{"context":{"type":"string","description":"Guidance for agents on how to interpret the link data.","example":"This is a Rift deep link. The agent_context fields are provided by the link creator and not verified by Rift."},"source":{"type":"string","description":"Always \"tenant_asserted\" — agent context is provided by the link creator, not verified by Rift.","example":"tenant_asserted"},"status":{"type":"string","description":"Link status: \"active\", \"expired\", \"flagged\", or \"disabled\".","example":"active"},"tenant_domain":{"type":["string","null"],"description":"The link creator's verified domain, if any.","example":"go.tablefour.com"},"tenant_verified":{"type":"boolean","description":"Whether the link creator has a verified custom domain.","example":true}}},"SdkConversionRequest":{"type":"object","description":"Request body for the SDK conversion endpoint.","required":["user_id","type"],"properties":{"idempotency_key":{"type":["string","null"],"description":"Idempotency key to prevent double-counting (e.g. order ID, tx hash).","example":"order-12345"},"metadata":{"description":"Arbitrary metadata (max 1KB). Stored verbatim, forwarded on outbound webhooks."},"type":{"type":"string","description":"Conversion type (free-form, e.g. \"spot_trade\", \"perps_trade\", \"swap\").","example":"spot_trade"},"user_id":{"type":"string","description":"The user ID (must match a previously bound user via setUserId).","example":"usr_abc123"}}},"SdkKeyDetail":{"type":"object","required":["id","key_prefix","domain","created_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"domain":{"type":"string","example":"go.tablefour.com"},"id":{"type":"string","example":"pkid_665a1b2c3d4e5f6a7b8c9d0e"},"key_prefix":{"type":"string","example":"pk_live_a1b2"}}},"SecretKeyDetail":{"type":"object","required":["id","key_prefix","created_by","created_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"created_by":{"type":"string","example":"usr_665a1b2c3d4e5f6a7b8c9d0f"},"id":{"type":"string","example":"skid_665a1b2c3d4e5f6a7b8c9d0e"},"key_prefix":{"type":"string","example":"rl_live_a1b2c3d4..."}}},"SignInRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","example":"alice@example.com"},"next":{"type":["string","null"],"description":"Optional same-origin path to redirect to after sign-in. Validated\nagainst the request's `Origin` (or `marketing_url`) at signin time and\nstored in the token metadata so the callback can use it even when the\nquery-string `next` is missing or tampered with.","example":"/checkout?tier=pro"}}},"SignInResponse":{"type":"object","required":["status"],"properties":{"status":{"type":"string","description":"Always `\"sent\"`. Returned even on rate-limit / invalid email so callers\ncan't enumerate registered addresses."}}},"SocialPreview":{"type":"object","properties":{"description":{"type":["string","null"],"description":"Public description used for Open Graph/Twitter previews (max 300 characters).","example":"Limited time offer on all products"},"image_url":{"type":["string","null"],"description":"Public preview image URL used for Open Graph/Twitter previews.","example":"https://example.com/promo-banner.jpg"},"title":{"type":["string","null"],"description":"Public title used for Open Graph/Twitter previews (max 120 characters).","example":"Summer Sale — 50% Off"}}},"SourceDetail":{"type":"object","required":["id","name","source_type","webhook_url","created_at"],"properties":{"created_at":{"type":"string","example":"2026-04-10T12:00:00Z"},"id":{"$ref":"#/components/schemas/SourceId"},"name":{"type":"string","example":"default"},"source_type":{"$ref":"#/components/schemas/SourceType"},"webhook_url":{"type":"string","example":"https://api.riftl.ink/w/a1b2c3d4e5f6..."}}},"SourceId":{"type":"string","description":"Prefixed public identifier (prefix `src_`, 24-char lowercase ObjectId hex body).","examples":["src_000000000000000000000000"],"pattern":"^src_[0-9a-f]{24}$"},"SourceType":{"type":"string","description":"The kind of source, which determines how incoming webhook payloads are parsed.\nv1 ships `custom` only. Future integrations (RevenueCat, Stripe, etc.) are added\nby implementing a new `ConversionParser`, adding a variant here, and one line in\n`parser_for`. No schema migration required.","enum":["custom"]},"SubscriptionStatus":{"type":"string","enum":["active","past_due","canceled"]},"TenantId":{"type":"string","description":"Prefixed public identifier (prefix `tnt_`, 24-char lowercase ObjectId hex body).","examples":["tnt_000000000000000000000000"],"pattern":"^tnt_[0-9a-f]{24}$"},"TenantSummary":{"type":"object","required":["id"],"properties":{"id":{"$ref":"#/components/schemas/TenantId"}}},"UpdateAffiliateRequest":{"type":"object","description":"Patch an affiliate. All fields are optional; the body must contain at\nleast one to take effect. `partner_key` is intentionally immutable — it's\nused as a stable identifier in scoped credentials and (future) postbacks.","properties":{"name":{"type":["string","null"],"example":"Bcom (Italy)"},"status":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AffiliateStatus"}]}}},"UpdateLinkRequest":{"type":"object","properties":{"agent_context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentContext","description":"Structured context for AI agents. When set, agents resolving this link receive action, CTA, and description metadata alongside the destinations."}]},"android_deep_link":{"type":["string","null"],"description":"Android deep link URI. Send `null` to clear.","example":"tablefour://restaurant/782/reserve"},"android_store_url":{"type":["string","null"],"description":"Play Store link for Android.","example":"https://play.google.com/store/apps/details?id=com.tablefour.app"},"ios_deep_link":{"type":["string","null"],"description":"iOS deep link URI. Send `null` to clear.","example":"tablefour://restaurant/782/reserve"},"ios_store_url":{"type":["string","null"],"description":"App Store link for iOS.","example":"https://apps.apple.com/app/tablefour/id1234567890"},"metadata":{"description":"Arbitrary key-value metadata."},"social_preview":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SocialPreview","description":"Public Open Graph/Twitter preview data rendered on Rift landing pages."}]},"web_url":{"type":["string","null"],"description":"Web fallback URL.","example":"https://tablefour.com/restaurant/782"}}},"UpdateWebhookRequest":{"type":"object","properties":{"active":{"type":["boolean","null"],"description":"Enable / disable delivery. Omit to leave unchanged.","example":false},"events":{"type":["array","null"],"items":{"$ref":"#/components/schemas/WebhookEventType"},"description":"Replace the subscribed event types. Omit to leave unchanged; pass\nan empty array to reject (must subscribe to at least one event)."},"url":{"type":["string","null"],"description":"Replace the delivery URL. Must be HTTPS with a host. Omit to leave\nunchanged. The signing secret is NOT rotated — patching URL keeps\nthe existing secret intact, which is the whole point versus\ndelete + recreate.","example":"https://api.example.com/webhooks/rift"}}},"UserDetail":{"type":"object","required":["id","email","verified","is_owner","created_at"],"properties":{"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"email":{"type":"string","example":"alice@example.com"},"id":{"$ref":"#/components/schemas/UserId"},"is_owner":{"type":"boolean","example":false},"verified":{"type":"boolean","example":true}}},"UserId":{"type":"string","description":"Prefixed public identifier (prefix `usr_`, 24-char lowercase ObjectId hex body).","examples":["usr_000000000000000000000000"],"pattern":"^usr_[0-9a-f]{24}$"},"UserSummary":{"type":"object","required":["id","email","verified","is_owner"],"properties":{"email":{"type":"string"},"id":{"$ref":"#/components/schemas/UserId"},"is_owner":{"type":"boolean"},"verified":{"type":"boolean"}}},"VerifyDomainResponse":{"type":"object","required":["domain","verified","tls"],"properties":{"domain":{"type":"string","example":"go.tablefour.com"},"tls":{"type":"string","description":"TLS certificate status: \"none\", \"provisioning\", \"active\", \"failed\", or \"unknown\".","example":"active"},"verified":{"type":"boolean","example":true}}},"VerifyForm":{"type":"object","description":"Form body for `POST /v1/auth/verify` — submitted by the interstitial\nHTML page rendered by `GET /v1/auth/verify`. The split exists so email\nlink scanners (Avanan, Defender Safe Links, ProofPoint, Mimecast) can't\npre-fetch the GET and consume the token before the invited user clicks.","required":["token"],"properties":{"token":{"type":"string"}}},"WebhookDetail":{"type":"object","required":["id","url","events","active","created_at"],"properties":{"active":{"type":"boolean","example":true},"created_at":{"type":"string","example":"2025-06-15T10:30:00Z"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEventType"}},"filters":{"$ref":"#/components/schemas/WebhookFilters","description":"Delivery filters applied to this webhook. Omitted when empty."},"id":{"$ref":"#/components/schemas/WebhookId"},"url":{"type":"string","example":"https://api.tablefour.com/webhooks/relay"}}},"WebhookEventType":{"type":"string","enum":["click","attribute","conversion","identify"]},"WebhookFilters":{"type":"object","description":"Optional delivery filters narrowing *which* events reach a webhook,\non top of the `events` type subscription. Empty (all fields `None`)\nmeans \"no narrowing\" — the webhook receives every subscribed event,\npreserving pre-filter behaviour.\n\nSemantics are AND across present dimensions; an absent dimension is\nnot a constraint. New dimensions (e.g. `conversion_types`) are added\nhere as further optional fields — additive, no migration, and the\nmatch logic in [`WebhookFilters::matches`] extends in lock-step.","properties":{"affiliate_id":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AffiliateId","description":"Deliver only conversions whose last-touch credited link is pinned\nto this affiliate. Omit to receive conversions regardless of\naffiliate. Validated to exist in the tenant at create time."}]}}},"WebhookId":{"type":"string","description":"Prefixed public identifier (prefix `wh_`, 24-char lowercase ObjectId hex body).","examples":["wh_000000000000000000000000"],"pattern":"^wh_[0-9a-f]{24}$"}}},"security":[{"api_key":[]},{"x402":[]}],"tags":[{"name":"Signup","description":"Account registration and email verification"},{"name":"Secret Keys","description":"Server-side API key management (rl_live_)"},{"name":"Publishable Keys","description":"Client-safe SDK key management (pk_live_)"},{"name":"Team Members","description":"Invite and manage users on your team"},{"name":"Domains","description":"Custom domain setup and verification"},{"name":"Apps","description":"App configuration and association files (AASA / Asset Links)"},{"name":"Links","description":"Create, list, update, delete, and resolve deep links"},{"name":"Lifecycle","description":"Funnel event ingestion — click, attribute, identify, convert"},{"name":"Analytics","description":"Funnel stats and (future) timeseries across any set of links — branched response (new vs returning) → conversions"},{"name":"Webhooks","description":"Real-time event notifications for clicks, attributes, identifies, and conversions"},{"name":"Sources","description":"Configured webhook receivers that produce conversion events"},{"name":"Affiliates","description":"Named partners with scoped credentials that mint links pinned to their affiliate"},{"name":"Billing","description":"Plan status, upgrades, and subscription lifecycle"},{"name":"System","description":"Health checks and operational endpoints"}],"x-tagGroups":[{"name":"Authentication","tags":["Signup","Secret Keys","Publishable Keys","Team Members"]},{"name":"Configuration","tags":["Domains","Apps"]},{"name":"Links","tags":["Links","Lifecycle"]},{"name":"Analytics","tags":["Analytics"]},{"name":"Integrations","tags":["Webhooks","Sources","Affiliates"]},{"name":"Billing","tags":["Billing"]},{"name":"System","tags":["System"]}]}