aboutsummaryrefslogtreecommitdiff
path: root/jb-ui
diff options
context:
space:
mode:
Diffstat (limited to 'jb-ui')
-rw-r--r--jb-ui/.vscode/settings.json14
-rw-r--r--jb-ui/Jenkinsfile10
-rw-r--r--jb-ui/src/JBApp.tsx405
-rw-r--r--jb-ui/src/api_fsb/.openapi-generator/FILES23
-rw-r--r--jb-ui/src/api_fsb/api.ts1650
-rw-r--r--jb-ui/src/api_fsb/docs/AccessType.md19
-rw-r--r--jb-ui/src/api_fsb/docs/AccountType.md2
-rw-r--r--jb-ui/src/api_fsb/docs/Amount.md19
-rw-r--r--jb-ui/src/api_fsb/docs/AttemptCreditClaimBody.md20
-rw-r--r--jb-ui/src/api_fsb/docs/AttemptCreditClaimResponse.md20
-rw-r--r--jb-ui/src/api_fsb/docs/BrokerageProductPayoutEvent.md6
-rw-r--r--jb-ui/src/api_fsb/docs/CashoutMethodOut.md2
-rw-r--r--jb-ui/src/api_fsb/docs/ContestEntry.md32
-rw-r--r--jb-ui/src/api_fsb/docs/ContestEntryType.md11
-rw-r--r--jb-ui/src/api_fsb/docs/GeoIPInformation.md2
-rw-r--r--jb-ui/src/api_fsb/docs/Leaderboard.md8
-rw-r--r--jb-ui/src/api_fsb/docs/LeaderboardRow.md2
-rw-r--r--jb-ui/src/api_fsb/docs/LedgerAccount.md2
-rw-r--r--jb-ui/src/api_fsb/docs/ManageCashoutBody.md22
-rw-r--r--jb-ui/src/api_fsb/docs/OfferwallApi.md243
-rw-r--r--jb-ui/src/api_fsb/docs/OrderData1.md37
-rw-r--r--jb-ui/src/api_fsb/docs/PayoutTransformation.md2
-rw-r--r--jb-ui/src/api_fsb/docs/Product.md2
-rw-r--r--jb-ui/src/api_fsb/docs/ProductBalances.md2
-rw-r--r--jb-ui/src/api_fsb/docs/ProfilingConfig.md6
-rw-r--r--jb-ui/src/api_fsb/docs/SupplyPolicy.md2
-rw-r--r--jb-ui/src/api_fsb/docs/THLApi.md60
-rw-r--r--jb-ui/src/api_fsb/docs/UpkQuestion.md2
-rw-r--r--jb-ui/src/api_fsb/docs/UpkQuestionOut.md2
-rw-r--r--jb-ui/src/api_fsb/docs/UserCpi.md19
-rw-r--r--jb-ui/src/api_fsb/docs/UserDisplayedWalletBalance.md25
-rw-r--r--jb-ui/src/api_fsb/docs/UserLedgerTransactionTaskComplete.md2
-rw-r--r--jb-ui/src/api_fsb/docs/UserLedgerWallet.md37
-rw-r--r--jb-ui/src/api_fsb/docs/UserLedgerWallets.md22
-rw-r--r--jb-ui/src/api_fsb/docs/UserPayoutEvent.md45
-rw-r--r--jb-ui/src/api_fsb/docs/UserProfile.md2
-rw-r--r--jb-ui/src/api_fsb/docs/UserWalletConfig.md6
-rw-r--r--jb-ui/src/api_fsb/docs/ValidationError.md4
-rw-r--r--jb-ui/src/api_fsb/docs/WallOut.md2
-rw-r--r--jb-ui/src/api_fsb/docs/WalletApi.md169
-rw-r--r--jb-ui/src/api_fsb/openapi.json2
-rw-r--r--jb-ui/src/components/EventMarquee.tsx428
-rw-r--r--jb-ui/src/components/Footer.tsx77
-rw-r--r--jb-ui/src/components/Profiling.tsx1313
-rw-r--r--jb-ui/src/components/Redemption.tsx61
-rw-r--r--jb-ui/src/components/Wallet.tsx866
-rw-r--r--jb-ui/src/components/ui/button.tsx20
-rw-r--r--jb-ui/src/components/ui/checkbox.tsx14
-rw-r--r--jb-ui/src/components/ui/confetti.tsx98
-rw-r--r--jb-ui/src/components/ui/dot-pattern.tsx60
-rw-r--r--jb-ui/src/components/ui/field.tsx72
-rw-r--r--jb-ui/src/components/ui/label.tsx12
-rw-r--r--jb-ui/src/components/ui/magic-card.tsx70
-rw-r--r--jb-ui/src/components/ui/pagination.tsx30
-rw-r--r--jb-ui/src/components/ui/separator.tsx14
-rw-r--r--jb-ui/src/components/ui/skeleton.tsx6
-rw-r--r--jb-ui/src/hooks.ts10
-rw-r--r--jb-ui/src/index.css1
-rw-r--r--jb-ui/src/lib/utils.ts164
-rw-r--r--jb-ui/src/main.tsx24
-rw-r--r--jb-ui/src/models/app.ts66
-rw-r--r--jb-ui/src/models/appSlice.ts353
-rw-r--r--jb-ui/src/models/authAPI.ts24
-rw-r--r--jb-ui/src/models/cashoutMethodsSlice.ts37
-rw-r--r--jb-ui/src/models/grlEventsSlice.ts74
-rw-r--r--jb-ui/src/models/grlStatsSlice.ts67
-rw-r--r--jb-ui/src/models/profilingQuestionsSlice.ts672
-rw-r--r--jb-ui/src/models/profilingUtils.ts309
-rw-r--r--jb-ui/src/pages/Home.tsx12
-rw-r--r--jb-ui/src/pages/MagicLink.tsx46
-rw-r--r--jb-ui/src/pages/Preview.tsx609
-rw-r--r--jb-ui/src/pages/Result.tsx198
-rw-r--r--jb-ui/src/pages/Transfer.tsx162
-rw-r--r--jb-ui/src/pages/Work.tsx1435
-rw-r--r--jb-ui/src/store.ts48
-rw-r--r--jb-ui/src/types/authApi.ts6
-rw-r--r--jb-ui/src/vite-env.d.ts16
-rw-r--r--jb-ui/tests/base.test.ts6
-rw-r--r--jb-ui/tests/setupTests.ts2
-rw-r--r--jb-ui/vite.config.ts102
80 files changed, 5847 insertions, 4699 deletions
diff --git a/jb-ui/.vscode/settings.json b/jb-ui/.vscode/settings.json
index aef94ef..9b8250c 100644
--- a/jb-ui/.vscode/settings.json
+++ b/jb-ui/.vscode/settings.json
@@ -1,3 +1,15 @@
{
- "editor.rulers": [80, 120]
+ "editor.rulers": [
+ 80,
+ 120
+ ],
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true,
+ "[typescriptreact]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": true
+ },
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": "explicit"
+ }
} \ No newline at end of file
diff --git a/jb-ui/Jenkinsfile b/jb-ui/Jenkinsfile
index 27a0ab9..97b8771 100644
--- a/jb-ui/Jenkinsfile
+++ b/jb-ui/Jenkinsfile
@@ -82,7 +82,7 @@ pipeline {
expression { env.BRANCH_NAME == 'master' }
}
steps {
- sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ thl-cdn:/root/amt-jb-cdn/"
+ sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ cdn-jb:/var/www/amt-jb-cdn/"
}
}
@@ -99,9 +99,9 @@ pipeline {
dir(env.BUILD_DIR) {
sh "cp ${env.JS_FILENAME}.js ${versioned_js}.js"
- sh "cp ${env.CSS_FILENAME}.js ${versioned_css}.js"
+ sh "cp ${env.CSS_FILENAME}.css ${versioned_css}.css"
- sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ thl-cdn:/root/amt-jb-cdn/"
+ sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ cdn-jb:/var/www/amt-jb-cdn/"
}
}
}
@@ -124,9 +124,9 @@ pipeline {
dir(env.BUILD_DIR) {
sh "cp ${env.JS_FILENAME}.js ${versioned}.js"
- sh "cp ${env.CSS_FILENAME}.js ${versioned}.js"
+ sh "cp ${env.CSS_FILENAME}.css ${versioned}.css"
- sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ thl-cdn:/root/amt-jb-cdn/"
+ sh "/usr/bin/rsync -avz ${WORKSPACE}/jb-ui/${env.BUILD_DIR}/ cdn-jb:/var/www/amt-jb-cdn/"
}
}
}
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx
index 76e3f29..c55cd73 100644
--- a/jb-ui/src/JBApp.tsx
+++ b/jb-ui/src/JBApp.tsx
@@ -1,29 +1,52 @@
import {
- EventMessage,
- EventType,
- PingMessage,
- PongMessage,
- PongMessageKindEnum,
- StatsMessage,
- StatusApi,
- SubscribeMessage, SubscribeMessageKindEnum,
- TaskStatusResponse,
- UserWalletBalance,
- UserWalletBalanceResponse,
- WalletApi
+ EventMessage,
+ EventType,
+ PingMessage,
+ PongMessage,
+ PongMessageKindEnum,
+ StatsMessage,
+ StatusApi,
+ SubscribeMessage,
+ SubscribeMessageKindEnum,
+ TaskStatusResponse,
+ UserWalletBalance,
+ UserWalletBalanceResponse,
+ UserLedgerWallets,
+ UserLedgerWalletAccountTypeEnum,
+ WalletApi,
+ CashoutMethodsResponse,
} from "@/api_fsb";
import Footer from "@/components/Footer";
import { useAppDispatch } from "@/hooks";
import { bpid, routeBasename, tagManager } from "@/lib/utils";
-import { setAssignmentID, setProductUserID, setTurkSubmitTo } from "@/models/appSlice";
+import { useGetMeQuery } from "@/models/authAPI";
+import {
+ setAssignmentID,
+ setProductUserID,
+ setUserDisplayedWalletBalance,
+ setUserWallet,
+ setUserAttemptCreditWallet,
+} from "@/models/appSlice";
+
+import { addCashoutMethods } from "@/models/cashoutMethodsSlice";
+
import { addEvent } from "@/models/grlEventsSlice";
import { addStatsData } from "@/models/grlStatsSlice";
-import Home from "@/pages/Home";
-import Preview from "@/pages/Preview";
+import MagicLink from "@/pages/MagicLink";
import Result from "@/pages/Result";
+import clsx from "clsx";
+
import Work from "@/pages/Work";
-import { BrowserRouter, Outlet, Route, Routes, useSearchParams } from "react-router-dom";
-import useWebSocket from 'react-use-websocket';
+import Transfer from "@/pages/Transfer";
+import {
+ BrowserRouter,
+ Outlet,
+ useMatch,
+ Route,
+ Routes,
+ useSearchParams,
+} from "react-router-dom";
+import useWebSocket from "react-use-websocket";
import NewsTicker from "./components/EventMarquee";
import { useEffect } from "react";
@@ -32,178 +55,234 @@ import Wallet from "@/components/Wallet";
import "@/index.css";
import { setTaskStatus, setUserWalletBalance } from "@/models/appSlice";
import { Profiling } from "./components/Profiling";
+import Redemption from "./components/Redemption";
-type Message = PingMessage | PongMessage | SubscribeMessage | EventMessage | StatsMessage;
+type Message =
+ | PingMessage
+ | PongMessage
+ | SubscribeMessage
+ | EventMessage
+ | StatsMessage;
function isStatsMessage(msg: Message): msg is StatsMessage {
- return msg.kind === 'stats';
+ return msg.kind === "stats";
}
function isEventMessage(msg: Message): msg is EventMessage {
- return msg.kind === 'event';
+ return msg.kind === "event";
}
function isPingMessage(msg: Message): msg is PingMessage {
- return msg.kind === 'ping';
+ return msg.kind === "ping";
}
function QueryParamProcessor() {
- const dispatch = useAppDispatch()
- const [searchParams] = useSearchParams();
+ const dispatch = useAppDispatch();
+ const [searchParams] = useSearchParams();
+ const { data: user } = useGetMeQuery();
- useEffect(() => {
- const worker_id = searchParams.get('workerId');
- const assignment_id = searchParams.get('assignmentId');
- const tsid = searchParams.get('tsid');
- const turkSubmitTo = searchParams.get('turkSubmitTo');
+ useEffect(() => {
+ if (user?.product_user_id) {
+ dispatch(setProductUserID(user.product_user_id));
- if (turkSubmitTo) {
- dispatch(setTurkSubmitTo(turkSubmitTo))
- }
+ new WalletApi()
+ .getCashoutMethodsProductIdCashoutMethodsGet(bpid, user.product_user_id)
+ .then((res) => {
+ const response = res.data as CashoutMethodsResponse;
+ dispatch(addCashoutMethods(response.cashout_methods));
+ });
- if (worker_id) {
- dispatch(setProductUserID(worker_id))
-
- new WalletApi().getUserWalletBalanceProductIdWalletGet(
- bpid, // productId
- worker_id, // bpuid
- ).then(res => {
- const response = res.data as UserWalletBalanceResponse;
- const balance = response.wallet as UserWalletBalance;
- dispatch(setUserWalletBalance(balance));
- });
- }
+ new WalletApi()
+ .getUserWalletBalanceProductIdWalletGet(
+ bpid, // productId
+ user.product_user_id,
+ )
+ .then((res) => {
+ const response = res.data as UserWalletBalanceResponse;
+ const balance = response.wallet as UserWalletBalance;
+ dispatch(setUserWalletBalance(balance));
+ });
- if (assignment_id) {
- dispatch(setAssignmentID(assignment_id))
- }
+ new WalletApi()
+ .getUserWalletsProductIdWalletsGet(bpid, user.product_user_id)
+ .then((res) => {
+ const response = res.data as UserLedgerWallets;
- if (tsid) {
- new StatusApi().getTaskStatusProductIdStatusTsidGet(
- bpid, // productId
- tsid).then(res => {
- const response: TaskStatusResponse = res.data;
- dispatch(setTaskStatus(response))
- }).catch((error) => {
- console.error("Error fetching task status:", error);
- });
- }
+ if (response.displayed_balances) {
+ setUserDisplayedWalletBalance(response.displayed_balances[0]);
+ }
- }, [searchParams]);
+ const userWallet = response.wallets?.find(
+ (w) =>
+ w.account_type === UserLedgerWalletAccountTypeEnum.UserWallet,
+ );
+ if (userWallet) {
+ setUserWallet(userWallet);
+ }
- return <Outlet />;
+ const userAttemptCreditWallet = response.wallets?.find(
+ (w) =>
+ w.account_type ===
+ UserLedgerWalletAccountTypeEnum.UserAttemptCredit,
+ );
+ if (userAttemptCreditWallet) {
+ setUserAttemptCreditWallet(userAttemptCreditWallet);
+ }
+ });
+ }
+ }, [user]);
+
+ useEffect(() => {
+ const assignment_id = searchParams.get("assignmentId");
+ const tsid = searchParams.get("tsid");
+ const worker_id = searchParams.get("workerId");
+
+ if (worker_id) {
+ dispatch(setProductUserID(worker_id));
+ }
+
+ if (assignment_id) {
+ dispatch(setAssignmentID(assignment_id));
+ }
+
+ if (tsid) {
+ new StatusApi()
+ .getTaskStatusProductIdStatusTsidGet(
+ bpid, // productId
+ tsid,
+ )
+ .then((res) => {
+ const response: TaskStatusResponse = res.data;
+ dispatch(setTaskStatus(response));
+ })
+ .catch((error) => {
+ console.error("Error fetching task status:", error);
+ });
+ }
+ }, [searchParams]);
+
+ return <Outlet />;
}
const Layout = () => {
- return (
- <div className="flex flex-col min-h-screen">
- <header className="bg-amber-400 text-amber-950 py-2 text-center">
- <a href="https://www.reddit.com/r/Marketresearch/comments/1s2tl0o/open_letter_to_cint_supplier_quality_issues/" target="_blank">
- <h4 className="text-[12px]">
- Letter to Cint: supplier quality issues, and malware-linked panels.
- </h4>
- </a>
- </header>
-
- <main className="flex flex-1 bg-zinc-200">
- <div className="flex flex-col items-center justify-center flex-1">
- <div className="
- w-full max-w-full
- p-2 bg-white shadow-lg
- text-center space-y-4
- md:max-w-5/8 md:rounded-lg
- rounded-none
- ">
- <Wallet />
- <Profiling />
- <Outlet />
- </div>
- </div>
- </main >
-
- <footer className="bg-slate-700 text-zinc-200 p-2 text-center font-mono">
- <NewsTicker />
- <Footer />
- </footer>
-
- </div >
- );
+ const isWork = useMatch("/work/*");
+ const isPreview = useMatch("/preview/*");
+ const isSpecialSubview = Boolean(isWork || isPreview);
+
+ return (
+ <div className="flex flex-col min-h-screen">
+ <header className="bg-amber-400 text-amber-950 py-2 text-center">
+ <a
+ href="https://www.reddit.com/r/Marketresearch/comments/1s2tl0o/open_letter_to_cint_supplier_quality_issues/"
+ target="_blank"
+ >
+ <h4 className="text-[12px]">
+ Letter to Cint: supplier quality issues, and malware-linked panels.
+ </h4>
+ </a>
+ </header>
+
+ <main className="flex flex-1 bg-zinc-200">
+ <div className="flex flex-col items-center justify-center flex-1">
+ <div
+ className={clsx(
+ "w-full max-w-full p-2 bg-white shadow-lg text-center space-y-4 md:max-w-5/8 md:rounded-lg rounded-none",
+ isSpecialSubview && "border-6 border-amber-400",
+ )}
+ >
+ <Wallet />
+ <Profiling />
+ <Redemption />
+ <Outlet />
+ </div>
+ </div>
+ </main>
+
+ <footer className="bg-slate-700 text-zinc-200 p-2 text-center font-mono">
+ <NewsTicker />
+ <Footer />
+ </footer>
+ </div>
+ );
};
function JBApp() {
- const dispatch = useAppDispatch()
-
- const { sendJsonMessage, lastMessage } = useWebSocket(
- "wss://fsb.generalresearch.com/ws/events/", {
- onOpen: () => {
- const subscribe: SubscribeMessage = {
- "kind": SubscribeMessageKindEnum.Subscribe,
- "product_id": bpid
- }
- sendJsonMessage(subscribe)
+ const dispatch = useAppDispatch();
+
+ const { sendJsonMessage, lastMessage } = useWebSocket(
+ "wss://fsb.generalresearch.com/ws/events/",
+ {
+ onOpen: () => {
+ const subscribe: SubscribeMessage = {
+ kind: SubscribeMessageKindEnum.Subscribe,
+ product_id: bpid,
+ };
+ sendJsonMessage(subscribe);
+ },
+ },
+ );
+
+ useEffect(() => {
+ if (lastMessage !== null) {
+ let msg: Message = JSON.parse(lastMessage.data);
+
+ if (isStatsMessage(msg)) {
+ dispatch(addStatsData(msg.data));
+ } else if (isEventMessage(msg)) {
+ // For simplicity, we just log the event messages here.
+ // You can extend this to update the UI or trigger notifications as needed.
+
+ switch (msg.data.event_type) {
+ case EventType.TaskEnter:
+ case EventType.TaskFinish:
+ case EventType.UserCreated:
+ dispatch(addEvent(msg.data));
+ break;
+
+ default:
+ // do nothing for now
+ break;
}
+ } else if (isPingMessage(msg)) {
+ const pong: PongMessage = {
+ kind: PongMessageKindEnum.Pong,
+ };
+ sendJsonMessage(pong);
+ }
}
- );
-
- useEffect(() => {
- if (lastMessage !== null) {
- let msg: Message = JSON.parse(lastMessage.data);
-
- if (isStatsMessage(msg)) {
- dispatch(addStatsData(msg.data))
-
- } else if (isEventMessage(msg)) {
- // For simplicity, we just log the event messages here.
- // You can extend this to update the UI or trigger notifications as needed.
-
- switch (msg.data.event_type) {
- case EventType.TaskEnter:
- case EventType.TaskFinish:
- case EventType.UserCreated:
- dispatch(addEvent(msg.data));
- break
-
- default:
- // do nothing for now
- break;
- }
-
- } else if (isPingMessage(msg)) {
- const pong: PongMessage = {
- "kind": PongMessageKindEnum.Pong,
- }
- sendJsonMessage(pong)
- }
- }
- }, [lastMessage]);
-
- useEffect(() => {
- if (!tagManager) return;
-
- var _mtm = window._mtm = window._mtm || [];
- _mtm.push({ 'mtm.startTime': (new Date().getTime()), 'event': 'mtm.Start' });
- var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
- g.async = true;
- g.src = tagManager;
- if (s.parentNode) {
- s.parentNode.insertBefore(g, s);
- }
- }, [tagManager])
-
- return (
- <BrowserRouter basename={routeBasename}>
- <Routes>
- <Route element={<QueryParamProcessor />}>
- <Route element={<Layout />}>
- <Route path="/" element={<Home />} />
- <Route path="/preview/" element={<Preview />} />
- <Route path="/work/" element={<Work />} />
- <Route path="/result/" element={<Result />} />
- </Route>
- </Route>
- </Routes>
- </BrowserRouter>
- )
+ }, [lastMessage]);
+
+ useEffect(() => {
+ if (!tagManager) return;
+
+ var _mtm = (window._mtm = window._mtm || []);
+ _mtm.push({ "mtm.startTime": new Date().getTime(), event: "mtm.Start" });
+ var d = document,
+ g = d.createElement("script"),
+ s = d.getElementsByTagName("script")[0];
+ g.async = true;
+ g.src = tagManager;
+ if (s.parentNode) {
+ s.parentNode.insertBefore(g, s);
+ }
+ }, [tagManager]);
+
+ return (
+ <BrowserRouter basename={routeBasename}>
+ <Routes>
+ <Route element={<QueryParamProcessor />}>
+ <Route element={<Layout />}>
+ <Route path="/" element={<Work />} />
+ <Route path="/auth/magic-link/" element={<MagicLink />} />
+
+ <Route path="/preview/" element={<Transfer />} />
+ <Route path="/work/" element={<Transfer />} />
+ <Route path="/result/" element={<Result />} />
+ </Route>
+ </Route>
+ </Routes>
+ </BrowserRouter>
+ );
}
-export default JBApp; \ No newline at end of file
+export default JBApp;
diff --git a/jb-ui/src/api_fsb/.openapi-generator/FILES b/jb-ui/src/api_fsb/.openapi-generator/FILES
index d76611f..7416313 100644
--- a/jb-ui/src/api_fsb/.openapi-generator/FILES
+++ b/jb-ui/src/api_fsb/.openapi-generator/FILES
@@ -4,13 +4,17 @@ api.ts
base.ts
common.ts
configuration.ts
+docs/AccessType.md
docs/AccountType.md
docs/AdjustedAfter.md
docs/AdjustedBefore.md
docs/AdjustedTimestamp.md
docs/AdjustmentType.md
docs/AggregateBySource.md
+docs/Amount.md
docs/AmtCashoutMethodData.md
+docs/AttemptCreditClaimBody.md
+docs/AttemptCreditClaimResponse.md
docs/AuditLog.md
docs/AuditLogLevel.md
docs/Body.md
@@ -36,8 +40,10 @@ docs/ContestApi.md
docs/ContestEndCondition.md
docs/ContestEndConditionTargetEntryAmount.md
docs/ContestEndReason.md
+docs/ContestEntry.md
docs/ContestEntryRule.md
docs/ContestEntryTrigger.md
+docs/ContestEntryType.md
docs/ContestPrize.md
docs/ContestPrizeKind.md
docs/ContestStatus.md
@@ -77,6 +83,7 @@ docs/LedgerAccount.md
docs/LedgerEntry.md
docs/LedgerTransaction.md
docs/ListContestsUserEnteredProductIdContestUserProductUserIdEnteredGet200ResponseInner.md
+docs/ManageCashoutBody.md
docs/MarketProfileKnowledge.md
docs/MarketplaceBucket.md
docs/MarketplaceInventorySummary.md
@@ -96,6 +103,7 @@ docs/OneShotOfferwall.md
docs/OneShotOfferwallBucket.md
docs/OneShotOfferwallResponse.md
docs/OrderData.md
+docs/OrderData1.md
docs/POPFinancial.md
docs/PatternValidation.md
docs/Payload.md
@@ -132,9 +140,6 @@ docs/SessionFinishPayload.md
docs/SessionStatusCode2.md
docs/ShippingCarrier.md
docs/ShippingMethod.md
-docs/SingleEntryBucket.md
-docs/SingleEntryOfferWall.md
-docs/SingleEntryOfferWallResponse.md
docs/SoftPairBucket.md
docs/SoftPairOfferwall.md
docs/SoftPairOfferwallResponse.md
@@ -143,8 +148,6 @@ docs/SourceConfig.md
docs/SourcesConfig.md
docs/StartedAfter.md
docs/StartedBefore.md
-docs/StarwallOfferWall.md
-docs/StarwallOfferWallResponse.md
docs/StarwallPlusBlockOfferWall.md
docs/StarwallPlusBlockOfferWallResponse.md
docs/StarwallPlusBlockRecontactOfferWall.md
@@ -172,14 +175,12 @@ docs/SupplyConfig.md
docs/SupplyPolicy.md
docs/SurveyEligibilityCriterion.md
docs/SurveyId.md
+docs/THLApi.md
docs/TangoCashoutMethodData.md
docs/TaskEnterPayload.md
docs/TaskFinishPayload.md
docs/TaskStatusResponse.md
docs/TasksStatusResponse.md
-docs/TopNBucket.md
-docs/TopNOfferWall.md
-docs/TopNOfferWallResponse.md
docs/TopNPlusBlockOfferWall.md
docs/TopNPlusBlockOfferWallResponse.md
docs/TopNPlusBlockRecontactOfferWall.md
@@ -211,8 +212,10 @@ docs/Uri.md
docs/User.md
docs/UserAmount.md
docs/UserAmountToday.md
+docs/UserCpi.md
docs/UserCpiString.md
docs/UserCreateConfig.md
+docs/UserDisplayedWalletBalance.md
docs/UserHealthConfig.md
docs/UserInfo.md
docs/UserInfoResponse.md
@@ -224,6 +227,9 @@ docs/UserLedgerTransactionUserBonus.md
docs/UserLedgerTransactionUserPayout.md
docs/UserLedgerTransactionsResponse.md
docs/UserLedgerTransactionsResponseTransactionsInner.md
+docs/UserLedgerWallet.md
+docs/UserLedgerWallets.md
+docs/UserPayoutEvent.md
docs/UserProfile.md
docs/UserProfileKnowledge.md
docs/UserProfileKnowledgeAnswer.md
@@ -232,7 +238,6 @@ docs/UserProfileUpdateRequest.md
docs/UserProfilesResponse.md
docs/UserQuestionAnswerIn.md
docs/UserStreak.md
-docs/UserType.md
docs/UserWalletBalance.md
docs/UserWalletBalanceResponse.md
docs/UserWalletConfig.md
diff --git a/jb-ui/src/api_fsb/api.ts b/jb-ui/src/api_fsb/api.ts
index 6d0acea..d819c9c 100644
--- a/jb-ui/src/api_fsb/api.ts
+++ b/jb-ui/src/api_fsb/api.ts
@@ -24,6 +24,24 @@ import type { RequestArgs } from './base';
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base';
/**
+ * How the network is used
+ * @export
+ * @enum {string}
+ */
+
+export const AccessType = {
+ Residential: 'residential',
+ Mobile: 'mobile',
+ Satellite: 'satellite',
+ Datacenter: 'datacenter',
+ Enterprise: 'enterprise',
+ Unknown: 'unknown'
+} as const;
+
+export type AccessType = typeof AccessType[keyof typeof AccessType];
+
+
+/**
*
* @export
* @enum {string}
@@ -33,6 +51,7 @@ export const AccountType = {
BpCommission: 'bp_commission',
BpWallet: 'bp_wallet',
UserWallet: 'user_wallet',
+ UserAttemptCredit: 'user_attempt_credit',
Cash: 'cash',
Revenue: 'revenue',
Expense: 'expense',
@@ -109,6 +128,13 @@ export interface AggregateBySource {
'by_source'?: { [key: string]: number; };
}
/**
+ * The amount of the entry in integer counts or USD Cents
+ * @export
+ * @interface Amount
+ */
+export interface Amount {
+}
+/**
*
* @export
* @interface AmtCashoutMethodData
@@ -129,6 +155,32 @@ export const AmtCashoutMethodDataTypeEnum = {
export type AmtCashoutMethodDataTypeEnum = typeof AmtCashoutMethodDataTypeEnum[keyof typeof AmtCashoutMethodDataTypeEnum];
/**
+ *
+ * @export
+ * @interface AttemptCreditClaimBody
+ */
+export interface AttemptCreditClaimBody {
+ /**
+ * (product_user_id) The user requesting the claim
+ * @type {string}
+ * @memberof AttemptCreditClaimBody
+ */
+ 'bpuid': string;
+}
+/**
+ *
+ * @export
+ * @interface AttemptCreditClaimResponse
+ */
+export interface AttemptCreditClaimResponse {
+ /**
+ *
+ * @type {number}
+ * @memberof AttemptCreditClaimResponse
+ */
+ 'amount': number | null;
+}
+/**
* Table / Model for logging \"actions\" taken by a user or \"events\" that are related to a User
* @export
* @interface AuditLog
@@ -257,17 +309,17 @@ export interface BrokerageProductPayoutEvent {
*/
'uuid'?: string;
/**
- * The LedgerAccount.uuid that money is being requested from. Thie User or Brokerage Product is retrievable through the LedgerAccount.reference_uuid
+ *
* @type {string}
* @memberof BrokerageProductPayoutEvent
*/
- 'debit_account_uuid': string;
+ 'debit_account_uuid': string | null;
/**
- * References a row in the account_cashoutmethod table. This is the cashout method that was used to request this payout. (A cashout is the same thing as a payout)
+ *
* @type {string}
* @memberof BrokerageProductPayoutEvent
*/
- 'cashout_method_uuid': string;
+ 'cashout_method_uuid': string | null;
/**
*
* @type {string}
@@ -299,11 +351,11 @@ export interface BrokerageProductPayoutEvent {
*/
'payout_type': PayoutType;
/**
- * Stores payout-type-specific information that is used to request this payout from the external provider.
+ *
* @type {object}
* @memberof BrokerageProductPayoutEvent
*/
- 'request_data'?: object;
+ 'request_data'?: object | null;
/**
*
* @type {OrderData}
@@ -612,7 +664,7 @@ export interface CashoutMethodOut {
*/
'name': string;
/**
- * The method in which the requested payout is delivered. Allowed values: - __PAYPAL__ *(PAYPAL)*: User is paid out to their personal PayPal email address - __TANGO__ *(TANGO)*: User is paid uut via a Tango Gift Card - __DWOLLA__ *(DWOLLA)*: DWOLLA - __ACH__ *(ACH)*: A payment is made to a bank account using ACH - __WIRE__ *(WIRE)*: A payment is made to a bank account using ACH - __CASH_IN_MAIL__ *(CASH_IN_MAIL)*: A payment is made in cash and mailed to the user. - __PRIZE__ *(PRIZE)*: A payment is made as a prize with some monetary value - __AMT__ *(AMT)*: This is used to designate either AMT_BONUS or AMT_HIT - __AMT_BONUS__ *(AMT_BONUS)*: Amazon Mechanical Turk as a Bonus - __AMT_ASSIGNMENT__ *(AMT_HIT)*: Amazon Mechanical Turk for a HIT
+ * The method in which the requested payout is delivered. Allowed values: - __PAYPAL__ *(PAYPAL)*: User is paid out to their personal PayPal email address - __TANGO__ *(TANGO)*: User is paid out via a Tango Gift Card - __DWOLLA__ *(DWOLLA)*: DWOLLA - __ACH__ *(ACH)*: A payment is made to a bank account using ACH - __WIRE__ *(WIRE)*: A payment is made to a bank account using ACH - __CASH_IN_MAIL__ *(CASH_IN_MAIL)*: A payment is made in cash and mailed to the user. - __PRIZE__ *(PRIZE)*: A payment is made as a prize with some monetary value - __AMT__ *(AMT)*: This is used to designate either AMT_BONUS or AMT_HIT - __AMT_BONUS__ *(AMT_BONUS)*: Amazon Mechanical Turk as a Bonus - __AMT_ASSIGNMENT__ *(AMT_HIT)*: Amazon Mechanical Turk for a HIT
* @type {PayoutType}
* @memberof CashoutMethodOut
*/
@@ -916,6 +968,57 @@ export type ContestEndReason = typeof ContestEndReason[keyof typeof ContestEndRe
/**
+ *
+ * @export
+ * @interface ContestEntry
+ */
+export interface ContestEntry {
+ /**
+ *
+ * @type {string}
+ * @memberof ContestEntry
+ */
+ 'uuid'?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof ContestEntry
+ */
+ 'created_at'?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof ContestEntry
+ */
+ 'updated_at'?: string;
+ /**
+ *
+ * @type {ContestEntryType}
+ * @memberof ContestEntry
+ */
+ 'entry_type': ContestEntryType;
+ /**
+ *
+ * @type {Amount}
+ * @memberof ContestEntry
+ */
+ 'amount': Amount;
+ /**
+ *
+ * @type {string}
+ * @memberof ContestEntry
+ */
+ 'amount_str': string;
+ /**
+ *
+ * @type {string}
+ * @memberof ContestEntry
+ */
+ 'censored_product_user_id': string;
+}
+
+
+/**
* Defines rules the user must meet to be allowed to enter this contest Only applies if the ContestType is ENTRY!
* @export
* @interface ContestEntryRule
@@ -968,6 +1071,20 @@ export type ContestEntryTrigger = typeof ContestEntryTrigger[keyof typeof Contes
/**
+ * All entries into a contest must be of the same type, and match the entry_type of the Contest itself.
+ * @export
+ * @enum {string}
+ */
+
+export const ContestEntryType = {
+ Count: 'count',
+ Cash: 'cash'
+} as const;
+
+export type ContestEntryType = typeof ContestEntryType[keyof typeof ContestEntryType];
+
+
+/**
*
* @export
* @interface ContestPrize
@@ -1650,10 +1767,10 @@ export interface GeoIPInformation {
'static_ip_score'?: number | null;
/**
*
- * @type {UserType}
+ * @type {AccessType}
* @memberof GeoIPInformation
*/
- 'user_type'?: UserType | null;
+ 'user_type'?: AccessType | null;
/**
*
* @type {string}
@@ -1715,17 +1832,17 @@ export type IntegrationMode = typeof IntegrationMode[keyof typeof IntegrationMod
*/
export interface Leaderboard {
/**
- * Unique ID for this leaderboard
+ *
* @type {string}
* @memberof Leaderboard
*/
- 'id'?: string;
+ 'id'?: string | null;
/**
- * Descriptive name for the leaderboard based on the board_code
+ *
* @type {string}
* @memberof Leaderboard
*/
- 'name'?: string;
+ 'name'?: string | null;
/**
* The type of leaderboard. What the \"values\" represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @type {LeaderboardCode}
@@ -1751,11 +1868,11 @@ export interface Leaderboard {
*/
'freq': LeaderboardFrequency;
/**
- * The timezone for the requested country
+ *
* @type {string}
* @memberof Leaderboard
*/
- 'timezone_name'?: string;
+ 'timezone_name'?: string | null;
/**
*
* @type {string}
@@ -1781,11 +1898,11 @@ export interface Leaderboard {
*/
'period_start_local': string;
/**
- * The end of the time period covered by this board in local time, tz-aware
+ *
* @type {string}
* @memberof Leaderboard
*/
- 'period_end_local'?: string;
+ 'period_end_local'?: string | null;
/**
* (unix timestamp) The start time of the time range this leaderboard covers.
* @type {number}
@@ -2063,6 +2180,12 @@ export interface LeaderboardRow {
* @memberof LeaderboardRow
*/
'value': number;
+ /**
+ *
+ * @type {string}
+ * @memberof LeaderboardRow
+ */
+ 'display_name'?: string | null;
}
/**
*
@@ -2197,7 +2320,7 @@ export interface LedgerAccount {
*/
'qualified_name': string;
/**
- * - `bp_commission` = BP_COMMISSION - `bp_wallet` = BP_WALLET - `user_wallet` = USER_WALLET - `cash` = CASH - `revenue` = REVENUE - `expense` = EXPENSE - `contest_wallet` = CONTEST_WALLET - `credit_line` = CREDIT_LINE - `wa_wallet` = WA_WALLET - `wa_budget_pool` = WA_BUDGET_POOL - `wa_held` = WA_HELD - `wa_credit_line` = WA_CREDIT_LINE
+ * - `bp_commission` = BP_COMMISSION - `bp_wallet` = BP_WALLET - `user_wallet` = USER_WALLET - `user_attempt_credit` = USER_ATTEMPT_CREDIT - `cash` = CASH - `revenue` = REVENUE - `expense` = EXPENSE - `contest_wallet` = CONTEST_WALLET - `credit_line` = CREDIT_LINE - `wa_wallet` = WA_WALLET - `wa_budget_pool` = WA_BUDGET_POOL - `wa_held` = WA_HELD - `wa_credit_line` = WA_CREDIT_LINE
* @type {AccountType}
* @memberof LedgerAccount
*/
@@ -2545,6 +2668,27 @@ export const ListContestsUserEnteredProductIdContestUserProductUserIdEnteredGet2
export type ListContestsUserEnteredProductIdContestUserProductUserIdEnteredGet200ResponseInnerValidForEventEnum = typeof ListContestsUserEnteredProductIdContestUserProductUserIdEnteredGet200ResponseInnerValidForEventEnum[keyof typeof ListContestsUserEnteredProductIdContestUserProductUserIdEnteredGet200ResponseInnerValidForEventEnum];
/**
+ *
+ * @export
+ * @interface ManageCashoutBody
+ */
+export interface ManageCashoutBody {
+ /**
+ *
+ * @type {string}
+ * @memberof ManageCashoutBody
+ */
+ 'payout_id': string;
+ /**
+ *
+ * @type {PayoutStatus}
+ * @memberof ManageCashoutBody
+ */
+ 'new_status': PayoutStatus;
+}
+
+
+/**
* This is used solely in API responses, so it is simplified.
* @export
* @interface MarketProfileKnowledge
@@ -3258,6 +3402,74 @@ export const OrderDataTypeEnum = {
export type OrderDataTypeEnum = typeof OrderDataTypeEnum[keyof typeof OrderDataTypeEnum];
/**
+ * Stores payout-type-specific order information that is returned from the external payout provider.
+ * @export
+ * @interface OrderData1
+ */
+export interface OrderData1 {
+ /**
+ *
+ * @type {string}
+ * @memberof OrderData1
+ */
+ 'type'?: OrderData1TypeEnum;
+ /**
+ *
+ * @type {number}
+ * @memberof OrderData1
+ */
+ 'shipping_cost': number;
+ /**
+ *
+ * @type {string}
+ * @memberof OrderData1
+ */
+ 'tracking_number'?: string;
+ /**
+ *
+ * @type {ShippingMethod}
+ * @memberof OrderData1
+ */
+ 'shipping_method'?: ShippingMethod;
+ /**
+ *
+ * @type {ShippingCarrier}
+ * @memberof OrderData1
+ */
+ 'carrier'?: ShippingCarrier;
+ /**
+ *
+ * @type {string}
+ * @memberof OrderData1
+ */
+ 'ship_date'?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof OrderData1
+ */
+ 'estimated_delivery_date'?: string;
+ /**
+ *
+ * @type {DeliveryStatus}
+ * @memberof OrderData1
+ */
+ 'delivery_status'?: DeliveryStatus;
+ /**
+ *
+ * @type {string}
+ * @memberof OrderData1
+ */
+ 'last_updated'?: string;
+}
+
+export const OrderData1TypeEnum = {
+ CashInMail: 'CASH_IN_MAIL'
+} as const;
+
+export type OrderData1TypeEnum = typeof OrderData1TypeEnum[keyof typeof OrderData1TypeEnum];
+
+/**
* We can\'t use our USDCent class in here because aside from it not supporting negative values for our adjustments, FastAPI also complains because it doesn\'t know how to generate documentation for it. - Max 2024-06-25
* @export
* @interface POPFinancial
@@ -3430,7 +3642,7 @@ export interface PayoutSummary {
'upper_whisker': number;
}
/**
- * This model describe how the bp_payout is converted to the user_payout. If None, the user_payout is None. If the user_wallet_enabled is `False`, the user_payout is used to 1) know how to transform the expected payouts for offerwall buckets (if min_payout is requested, this is based on the user_payout) 2) show the user (using the payout_format) how much they made (in the Task Status Response). If the user_wallet_enabled is `True`, then in addition to the above, the user_payout is the amount actually paid to the user\'s wallet.
+ * This model describe how the bp_payout is converted to the user_payout. If None, the user_payout is None. If the user_wallet_enabled is `False`, the user_payout is used to 1) know how to transform the expected payouts for offerwall buckets (if min_payout is requested, this is based on the user_payout) 2) show the user (using the payout_format) how much they made (in the Task Status Response). If the user_wallet_enabled is `True`, then in addition to the above, the user_payout is the amount actually paid to the user\'s wallet.
* @export
* @interface PayoutTransformation
*/
@@ -3607,7 +3819,7 @@ export interface Product {
*/
'enabled'?: boolean;
/**
- * This is only to determine if ACH or Wire payments should be made to the Produce.
+ * This is only to determine if ACH or Wire payments should be made to the Product.
* @type {boolean}
* @memberof Product
*/
@@ -3890,7 +4102,7 @@ export interface ProductBalances {
*/
'available_balance_usd_str': string;
/**
- *
+ * The amount that must be held back to recover a negative Product balance. This is $0.00 when the Product balance is positive or zero; otherwise it is the absolute value of the negative balance. Business-level payout calculations use this amount to offset deficits from one Product against available funds from other Products before issuing Supplier Payments.
* @type {number}
* @memberof ProductBalances
*/
@@ -3921,7 +4133,7 @@ export interface ProfilingConfig {
*/
'enabled'?: boolean;
/**
- * If grs_enabled is False, and is_grs is passed in the profiling-questions call, then don\'t actually return any questions. This allows a client to hit the endpoint with no limit and still get questions. In effect, this means that we\'ll redirect the user through the GRS system but won\'t present them any questions.
+ * If grs_enabled is False, and is_grs is passed in the profiling-questions call, then don\'t actually return any questions. This allows a client to hit the endpoint with no limit and still get questions. In effect, this means that we\'ll redirect the user through the GRS system but won\'t present them any questions.
* @type {boolean}
* @memberof ProfilingConfig
*/
@@ -3945,13 +4157,13 @@ export interface ProfilingConfig {
*/
'avg_question_count'?: number;
/**
- * Scale how frequently we inject profiling questions, relative to the default.1 is default, 2 is twice as often. 10 means always. 0.5 half as often
+ * Scale how frequently we inject profiling questions, relative to the default. 1 is default, 2 is twice as often. 10 means always. 0.5 half as often
* @type {number}
* @memberof ProfilingConfig
*/
'task_injection_freq_mult'?: number;
/**
- * Non-us multiplier, used to increase freq and length of profilers in all non-us countries.This value is multiplied by task_injection_freq_mult and avg_question_count.
+ * Non-us multiplier, used to increase freq and length of profilers in all non-us countries. This value is multiplied by task_injection_freq_mult and avg_question_count.
* @type {number}
* @memberof ProfilingConfig
*/
@@ -4736,87 +4948,6 @@ export type ShippingMethod = typeof ShippingMethod[keyof typeof ShippingMethod];
/**
*
* @export
- * @interface SingleEntryBucket
- */
-export interface SingleEntryBucket {
- /**
- * Unique identifier this particular bucket
- * @type {string}
- * @memberof SingleEntryBucket
- */
- 'id': string;
- /**
- * The URL to send a respondent into. Must not edit this URL in any way
- * @type {string}
- * @memberof SingleEntryBucket
- */
- 'uri': string;
-}
-/**
- * Only returns a single bucket with the top scoring tasks. Offerwall code: `5fl8bpv5`
- * @export
- * @interface SingleEntryOfferWall
- */
-export interface SingleEntryOfferWall {
- /**
- * Unique identifier to reference a generated offerwall
- * @type {string}
- * @memberof SingleEntryOfferWall
- */
- 'id': string;
- /**
- * Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.
- * @type {number}
- * @memberof SingleEntryOfferWall
- */
- 'availability_count': number;
- /**
- * Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.
- * @type {number}
- * @memberof SingleEntryOfferWall
- */
- 'attempted_live_eligible_count'?: number;
- /**
- *
- * @type {Array<SingleEntryBucket>}
- * @memberof SingleEntryOfferWall
- */
- 'buckets'?: Array<SingleEntryBucket>;
- /**
- * Explanations describing why so many or few opportunities are available.
- * @type {Array<OfferwallReason>}
- * @memberof SingleEntryOfferWall
- */
- 'offerwall_reasons'?: Array<OfferwallReason>;
- /**
- * The format describing the str representation of a payout. Typically, this would be displayed to a user. The payout_format is similar to python format string with a subset of functionality supported. Only float with a precision are supported along with an optional comma for a thousands separator. In addition, a mathematical operator can be applied, such as dividing by 100. Examples are shown assuming payout = 100 (one dollar). - \"{payout*10:,.0f} Points\" -> \"1,000 Points\" - \"${payout/100:.2f}\" -> \"$1.00\"
- * @type {string}
- * @memberof SingleEntryOfferWall
- */
- 'payout_format': string;
-}
-/**
- *
- * @export
- * @interface SingleEntryOfferWallResponse
- */
-export interface SingleEntryOfferWallResponse {
- /**
- *
- * @type {OfferWallInfo}
- * @memberof SingleEntryOfferWallResponse
- */
- 'info': OfferWallInfo;
- /**
- *
- * @type {SingleEntryOfferWall}
- * @memberof SingleEntryOfferWallResponse
- */
- 'offerwall': SingleEntryOfferWall;
-}
-/**
- *
- * @export
* @interface SoftPairBucket
*/
export interface SoftPairBucket {
@@ -5066,68 +5197,6 @@ export interface StartedAfter {
export interface StartedBefore {
}
/**
- * An offerwall with buckets that are clustered by setting as seeds the highest scoring surveys for each bin, then the rest are distributed according to their Euclidean distance using the bucket\'s features. Offerwall code: `b59a2d2b`
- * @export
- * @interface StarwallOfferWall
- */
-export interface StarwallOfferWall {
- /**
- * Unique identifier to reference a generated offerwall
- * @type {string}
- * @memberof StarwallOfferWall
- */
- 'id': string;
- /**
- * Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.
- * @type {number}
- * @memberof StarwallOfferWall
- */
- 'availability_count': number;
- /**
- * Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.
- * @type {number}
- * @memberof StarwallOfferWall
- */
- 'attempted_live_eligible_count'?: number;
- /**
- *
- * @type {Array<TopNBucket>}
- * @memberof StarwallOfferWall
- */
- 'buckets'?: Array<TopNBucket>;
- /**
- * Explanations describing why so many or few opportunities are available.
- * @type {Array<OfferwallReason>}
- * @memberof StarwallOfferWall
- */
- 'offerwall_reasons'?: Array<OfferwallReason>;
- /**
- * The format describing the str representation of a payout. Typically, this would be displayed to a user. The payout_format is similar to python format string with a subset of functionality supported. Only float with a precision are supported along with an optional comma for a thousands separator. In addition, a mathematical operator can be applied, such as dividing by 100. Examples are shown assuming payout = 100 (one dollar). - \"{payout*10:,.0f} Points\" -> \"1,000 Points\" - \"${payout/100:.2f}\" -> \"$1.00\"
- * @type {string}
- * @memberof StarwallOfferWall
- */
- 'payout_format': string;
-}
-/**
- *
- * @export
- * @interface StarwallOfferWallResponse
- */
-export interface StarwallOfferWallResponse {
- /**
- *
- * @type {OfferWallInfo}
- * @memberof StarwallOfferWallResponse
- */
- 'info': OfferWallInfo;
- /**
- *
- * @type {StarwallOfferWall}
- * @memberof StarwallOfferWallResponse
- */
- 'offerwall': StarwallOfferWall;
-}
-/**
* Same as the StarwallOfferWall, but the buckets include contents and no buckets are returned if the user is blocked. Offerwall code: `7fa1b3f4`
* @export
* @interface StarwallPlusBlockOfferWall
@@ -5781,7 +5850,7 @@ export interface SupplyConfig {
'policies'?: Array<SupplyPolicy>;
}
/**
- * One policy describing how GRL can interact with a marketplaces in a certain way. This is only used on the special \"global product\", and then internally in grpc logic.
+ * One policy describing how GRL can interact with a marketplaces in a certain way. This is only used on the special \"global product\", and then internally in grpc logic.
* @export
* @interface SupplyPolicy
*/
@@ -6299,135 +6368,6 @@ export interface TasksStatusResponse {
'pages': number | null;
}
/**
- *
- * @export
- * @interface TopNBucket
- */
-export interface TopNBucket {
- /**
- * Unique identifier this particular bucket
- * @type {string}
- * @memberof TopNBucket
- */
- 'id': string;
- /**
- * The URL to send a respondent into. Must not edit this URL in any way
- * @type {string}
- * @memberof TopNBucket
- */
- 'uri': string;
- /**
- * For UI. Provides a dimensionality position for the bucket on the x-axis.
- * @type {number}
- * @memberof TopNBucket
- */
- 'x'?: number;
- /**
- * For UI. Provides a dimensionality position for the bucket on the y-axis.
- * @type {number}
- * @memberof TopNBucket
- */
- 'y'?: number;
- /**
- * Currently unused. Will always return empty string
- * @type {string}
- * @memberof TopNBucket
- */
- 'name'?: string;
- /**
- * Currently unused. Will always return empty string
- * @type {string}
- * @memberof TopNBucket
- */
- 'description'?: string;
- /**
- *
- * @type {Array<CategoryAssociation>}
- * @memberof TopNBucket
- */
- 'category'?: Array<CategoryAssociation>;
- /**
- *
- * @type {DurationSummary}
- * @memberof TopNBucket
- */
- 'duration': DurationSummary;
- /**
- *
- * @type {PayoutSummary}
- * @memberof TopNBucket
- */
- 'payout': PayoutSummary;
- /**
- * A proprietary score to determine the overall quality of the tasks that are within the bucket. Higher is better.
- * @type {number}
- * @memberof TopNBucket
- */
- 'quality_score': number;
-}
-/**
- * An offerwall with buckets that are clustered by the `split_by` argument using KMeans clustering. Offerwall code: `45b7228a7`
- * @export
- * @interface TopNOfferWall
- */
-export interface TopNOfferWall {
- /**
- * Unique identifier to reference a generated offerwall
- * @type {string}
- * @memberof TopNOfferWall
- */
- 'id': string;
- /**
- * Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.
- * @type {number}
- * @memberof TopNOfferWall
- */
- 'availability_count': number;
- /**
- * Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.
- * @type {number}
- * @memberof TopNOfferWall
- */
- 'attempted_live_eligible_count'?: number;
- /**
- *
- * @type {Array<TopNBucket>}
- * @memberof TopNOfferWall
- */
- 'buckets'?: Array<TopNBucket>;
- /**
- * Explanations describing why so many or few opportunities are available.
- * @type {Array<OfferwallReason>}
- * @memberof TopNOfferWall
- */
- 'offerwall_reasons'?: Array<OfferwallReason>;
- /**
- * The format describing the str representation of a payout. Typically, this would be displayed to a user. The payout_format is similar to python format string with a subset of functionality supported. Only float with a precision are supported along with an optional comma for a thousands separator. In addition, a mathematical operator can be applied, such as dividing by 100. Examples are shown assuming payout = 100 (one dollar). - \"{payout*10:,.0f} Points\" -> \"1,000 Points\" - \"${payout/100:.2f}\" -> \"$1.00\"
- * @type {string}
- * @memberof TopNOfferWall
- */
- 'payout_format': string;
-}
-/**
- *
- * @export
- * @interface TopNOfferWallResponse
- */
-export interface TopNOfferWallResponse {
- /**
- *
- * @type {OfferWallInfo}
- * @memberof TopNOfferWallResponse
- */
- 'info': OfferWallInfo;
- /**
- *
- * @type {TopNOfferWall}
- * @memberof TopNOfferWallResponse
- */
- 'offerwall': TopNOfferWall;
-}
-/**
* Same as the TopNOfferWall, but the buckets include contents and no buckets are returned if the user is blocked. Offerwall code: `d48cce47`
* @export
* @interface TopNPlusBlockOfferWall
@@ -6986,7 +6926,7 @@ export interface UpkQuestion {
* @type {Selector}
* @memberof UpkQuestion
*/
- 'selector'?: Selector;
+ 'selector': Selector;
/**
*
* @type {UpkQuestionConfiguration}
@@ -7234,7 +7174,7 @@ export interface UpkQuestionOut {
* @type {Selector}
* @memberof UpkQuestionOut
*/
- 'selector'?: Selector;
+ 'selector': Selector;
/**
*
* @type {UpkQuestionConfiguration}
@@ -7526,6 +7466,13 @@ export interface UserAmount {
export interface UserAmountToday {
}
/**
+ * The amount the user would earn from completing this task, if the status was a complete. If the BP has no payout xform, the user_cpi is None. This is analogous to the session\'s user_payout.
+ * @export
+ * @interface UserCpi
+ */
+export interface UserCpi {
+}
+/**
* If a payout transformation is configured on this account, this is the amount to display to the user
* @export
* @interface UserCpiString
@@ -7552,6 +7499,31 @@ export interface UserCreateConfig {
'max_hourly_create_limit'?: number | null;
}
/**
+ * Combined user-visible balance for one ledger currency.
+ * @export
+ * @interface UserDisplayedWalletBalance
+ */
+export interface UserDisplayedWalletBalance {
+ /**
+ *
+ * @type {string}
+ * @memberof UserDisplayedWalletBalance
+ */
+ 'currency': string;
+ /**
+ * Displayed balance in the currency\'s smallest ledger unit.
+ * @type {number}
+ * @memberof UserDisplayedWalletBalance
+ */
+ 'amount': number;
+ /**
+ *
+ * @type {string}
+ * @memberof UserDisplayedWalletBalance
+ */
+ 'amount_string'?: string | null;
+}
+/**
*
* @export
* @interface UserHealthConfig
@@ -7685,7 +7657,7 @@ export const UserLedgerTransactionTaskAdjustmentTxTypeEnum = {
export type UserLedgerTransactionTaskAdjustmentTxTypeEnum = typeof UserLedgerTransactionTaskAdjustmentTxTypeEnum[keyof typeof UserLedgerTransactionTaskAdjustmentTxTypeEnum];
/**
- * In a BP with user wallet enabled, the task-complete transaction would have line items for both the credit to the bp_wallet_account and credit to user_account. This is the user-detail, so we\'ve only caring about the user\'s payment.
+ * In a BP with user wallet enabled, the task-complete transaction would have line items for both the credit to the bp_wallet_account and credit to user_account. This is the user-detail, so we\'ve only caring about the user\'s payment.
* @export
* @interface UserLedgerTransactionTaskComplete
*/
@@ -7996,6 +7968,181 @@ export type UserLedgerTransactionsResponseStatusEnum = typeof UserLedgerTransact
export type UserLedgerTransactionsResponseTransactionsInner = { tx_type: 'bp_adjustment' } & UserLedgerTransactionTaskAdjustment | { tx_type: 'bp_payment' } & UserLedgerTransactionTaskComplete | { tx_type: 'user_bonus' } & UserLedgerTransactionUserBonus | { tx_type: 'user_payout_request' } & UserLedgerTransactionUserPayout;
/**
+ * A user-owned ledger account exposed by the wallets endpoint.
+ * @export
+ * @interface UserLedgerWallet
+ */
+export interface UserLedgerWallet {
+ /**
+ * (USD cents) The amount in the user\'s wallet.
+ * @type {number}
+ * @memberof UserLedgerWallet
+ */
+ 'amount': number;
+ /**
+ * (USD cents) The amount in the user\'s wallet this is currently redeemable.
+ * @type {number}
+ * @memberof UserLedgerWallet
+ */
+ 'redeemable_amount': number;
+ /**
+ *
+ * @type {string}
+ * @memberof UserLedgerWallet
+ */
+ 'payout_format'?: string | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserLedgerWallet
+ */
+ 'amount_string'?: string | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserLedgerWallet
+ */
+ 'redeemable_amount_string'?: string | null;
+ /**
+ * A unique identifier for this Ledger Account
+ * @type {string}
+ * @memberof UserLedgerWallet
+ */
+ 'account_uuid': string;
+ /**
+ *
+ * @type {string}
+ * @memberof UserLedgerWallet
+ */
+ 'account_type': UserLedgerWalletAccountTypeEnum;
+ /**
+ *
+ * @type {string}
+ * @memberof UserLedgerWallet
+ */
+ 'currency'?: string;
+ /**
+ * Human-readable description of the Ledger Account
+ * @type {string}
+ * @memberof UserLedgerWallet
+ */
+ 'display_name': string;
+}
+
+export const UserLedgerWalletAccountTypeEnum = {
+ UserWallet: 'user_wallet',
+ UserAttemptCredit: 'user_attempt_credit'
+} as const;
+
+export type UserLedgerWalletAccountTypeEnum = typeof UserLedgerWalletAccountTypeEnum[keyof typeof UserLedgerWalletAccountTypeEnum];
+
+/**
+ *
+ * @export
+ * @interface UserLedgerWallets
+ */
+export interface UserLedgerWallets {
+ /**
+ *
+ * @type {Array<UserLedgerWallet>}
+ * @memberof UserLedgerWallets
+ */
+ 'wallets'?: Array<UserLedgerWallet>;
+ /**
+ *
+ * @type {Array<UserDisplayedWalletBalance>}
+ * @memberof UserLedgerWallets
+ */
+ 'displayed_balances'?: Array<UserDisplayedWalletBalance>;
+}
+/**
+ * A user has requested to be paid from their wallet balance.
+ * @export
+ * @interface UserPayoutEvent
+ */
+export interface UserPayoutEvent {
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'uuid'?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'debit_account_uuid': string | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'cashout_method_uuid': string | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'created'?: string;
+ /**
+ * The USDCent amount int. This cannot be 0 or negative
+ * @type {number}
+ * @memberof UserPayoutEvent
+ */
+ 'amount': number;
+ /**
+ *
+ * @type {PayoutStatus}
+ * @memberof UserPayoutEvent
+ */
+ 'status'?: PayoutStatus | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'ext_ref_id'?: string | null;
+ /**
+ * - `PAYPAL` = PAYPAL - `TANGO` = TANGO - `DWOLLA` = DWOLLA - `ACH` = ACH - `WIRE` = WIRE - `CASH_IN_MAIL` = CASH_IN_MAIL - `PRIZE` = PRIZE - `AMT` = AMT - `AMT_BONUS` = AMT_BONUS - `AMT_ASSIGNMENT` = AMT_HIT
+ * @type {PayoutType}
+ * @memberof UserPayoutEvent
+ */
+ 'payout_type': PayoutType;
+ /**
+ *
+ * @type {object}
+ * @memberof UserPayoutEvent
+ */
+ 'request_data'?: object | null;
+ /**
+ *
+ * @type {OrderData1}
+ * @memberof UserPayoutEvent
+ */
+ 'order_data'?: OrderData1 | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'account_reference_type'?: string | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'account_reference_uuid'?: string | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserPayoutEvent
+ */
+ 'description'?: string | null;
+}
+
+
+/**
*
* @export
* @interface UserProfile
@@ -8009,6 +8156,12 @@ export interface UserProfile {
'email_address'?: string | null;
/**
*
+ * @type {string}
+ * @memberof UserProfile
+ */
+ 'display_name'?: string | null;
+ /**
+ *
* @type {User}
* @memberof UserProfile
*/
@@ -8288,33 +8441,6 @@ export interface UserStreak {
/**
*
* @export
- * @enum {string}
- */
-
-export const UserType = {
- Business: 'business',
- Cafe: 'cafe',
- Cellular: 'cellular',
- College: 'college',
- ContentDeliveryNetwork: 'content_delivery_network',
- ConsumerPrivacyNetwork: 'consumer_privacy_network',
- Government: 'government',
- Hosting: 'hosting',
- Library: 'library',
- Military: 'military',
- Residential: 'residential',
- Router: 'router',
- School: 'school',
- SearchEngineSpider: 'search_engine_spider',
- Traveler: 'traveler'
-} as const;
-
-export type UserType = typeof UserType[keyof typeof UserType];
-
-
-/**
- *
- * @export
* @interface UserWalletBalance
*/
export interface UserWalletBalance {
@@ -8395,6 +8521,12 @@ export interface UserWalletConfig {
*/
'enabled'?: boolean;
/**
+ * The balance used as the user\'s displayed balance.
+ * @type {string}
+ * @memberof UserWalletConfig
+ */
+ 'balance_type'?: UserWalletConfigBalanceTypeEnum;
+ /**
* Uses Amazon Mechanical Turk
* @type {boolean}
* @memberof UserWalletConfig
@@ -8402,17 +8534,31 @@ export interface UserWalletConfig {
'amt'?: boolean;
/**
*
- * @type {Set<PayoutType>}
+ * @type {Array<PayoutType>}
* @memberof UserWalletConfig
*/
- 'supported_payout_types'?: Set<PayoutType>;
+ 'supported_payout_types'?: Array<PayoutType>;
/**
*
* @type {string}
* @memberof UserWalletConfig
*/
'min_cashout'?: string | null;
+ /**
+ *
+ * @type {string}
+ * @memberof UserWalletConfig
+ */
+ 'failed_attempt_credit'?: string | null;
}
+
+export const UserWalletConfigBalanceTypeEnum = {
+ WalletBalance: 'wallet_balance',
+ RedeemableBalance: 'redeemable_balance'
+} as const;
+
+export type UserWalletConfigBalanceTypeEnum = typeof UserWalletConfigBalanceTypeEnum[keyof typeof UserWalletConfigBalanceTypeEnum];
+
/**
*
* @export
@@ -8437,6 +8583,18 @@ export interface ValidationError {
* @memberof ValidationError
*/
'type': string;
+ /**
+ *
+ * @type {any}
+ * @memberof ValidationError
+ */
+ 'input'?: any;
+ /**
+ *
+ * @type {object}
+ * @memberof ValidationError
+ */
+ 'ctx'?: object;
}
/**
*
@@ -8659,11 +8817,11 @@ export interface WallOut {
*/
'adjusted_timestamp'?: AdjustedTimestamp;
/**
- * The amount the user would earn from completing this task, if the status was a complete. If the BP has no payout xform, the user_cpi is None. This is analogous to the session\'s user_payout.
- * @type {number}
+ *
+ * @type {UserCpi}
* @memberof WallOut
*/
- 'user_cpi'?: number;
+ 'user_cpi'?: UserCpi;
/**
*
* @type {UserCpiString}
@@ -9227,11 +9385,11 @@ export const LeaderboardApiAxiosParamCreator = function (configuration?: Configu
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet: async (productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
+ leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet: async (productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'productId' is not null or undefined
assertParamExists('leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet', 'productId', productId)
// verify required parameter 'boardCode' is not null or undefined
@@ -9277,14 +9435,14 @@ export const LeaderboardApiAxiosParamCreator = function (configuration?: Configu
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {string} [bpuid] Brokerage Product User ID. If passed, this results in the filtering of rows to include this user\&#39;s row, plus rows above and below in rank (up to &#x60;limit&#x60; rows). Otherwise, the top &#x60;limit&#x60; rows are returned.
* @param {string} [withinTime] Any local timestamp falling within the desired leaderboard\&#39;s period. If not passed, uses the country\&#39;s current time period.
* @param {number} [limit] Max number of rows to return
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet: async (productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, bpuid?: string, withinTime?: string, limit?: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
+ timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet: async (productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, bpuid?: string, withinTime?: string, limit?: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'productId' is not null or undefined
assertParamExists('timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet', 'productId', productId)
// verify required parameter 'boardCode' is not null or undefined
@@ -9354,11 +9512,11 @@ export const LeaderboardApiFp = function(configuration?: Configuration) {
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<LeaderboardWinnerResponse>> {
+ async leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<LeaderboardWinnerResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId, boardCode, freq, countryIso, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['LeaderboardApi.leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet']?.[localVarOperationServerIndex]?.url;
@@ -9370,14 +9528,14 @@ export const LeaderboardApiFp = function(configuration?: Configuration) {
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {string} [bpuid] Brokerage Product User ID. If passed, this results in the filtering of rows to include this user\&#39;s row, plus rows above and below in rank (up to &#x60;limit&#x60; rows). Otherwise, the top &#x60;limit&#x60; rows are returned.
* @param {string} [withinTime] Any local timestamp falling within the desired leaderboard\&#39;s period. If not passed, uses the country\&#39;s current time period.
* @param {number} [limit] Max number of rows to return
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, bpuid?: string, withinTime?: string, limit?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<LeaderboardResponse>> {
+ async timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, bpuid?: string, withinTime?: string, limit?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<LeaderboardResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId, boardCode, freq, countryIso, bpuid, withinTime, limit, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['LeaderboardApi.timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet']?.[localVarOperationServerIndex]?.url;
@@ -9399,11 +9557,11 @@ export const LeaderboardApiFactory = function (configuration?: Configuration, ba
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, options?: RawAxiosRequestConfig): AxiosPromise<LeaderboardWinnerResponse> {
+ leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, options?: RawAxiosRequestConfig): AxiosPromise<LeaderboardWinnerResponse> {
return localVarFp.leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId, boardCode, freq, countryIso, options).then((request) => request(axios, basePath));
},
/**
@@ -9412,14 +9570,14 @@ export const LeaderboardApiFactory = function (configuration?: Configuration, ba
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {string} [bpuid] Brokerage Product User ID. If passed, this results in the filtering of rows to include this user\&#39;s row, plus rows above and below in rank (up to &#x60;limit&#x60; rows). Otherwise, the top &#x60;limit&#x60; rows are returned.
* @param {string} [withinTime] Any local timestamp falling within the desired leaderboard\&#39;s period. If not passed, uses the country\&#39;s current time period.
* @param {number} [limit] Max number of rows to return
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, bpuid?: string, withinTime?: string, limit?: number, options?: RawAxiosRequestConfig): AxiosPromise<LeaderboardResponse> {
+ timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, bpuid?: string, withinTime?: string, limit?: number, options?: RawAxiosRequestConfig): AxiosPromise<LeaderboardResponse> {
return localVarFp.timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId, boardCode, freq, countryIso, bpuid, withinTime, limit, options).then((request) => request(axios, basePath));
},
};
@@ -9438,12 +9596,12 @@ export class LeaderboardApi extends BaseAPI {
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof LeaderboardApi
*/
- public leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, options?: RawAxiosRequestConfig) {
+ public leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, options?: RawAxiosRequestConfig) {
return LeaderboardApiFp(this.configuration).leaderboardWinnersProductIdLeaderboardTimespanBoardCodeWinnersGet(productId, boardCode, freq, countryIso, options).then((request) => request(this.axios, this.basePath));
}
@@ -9453,7 +9611,7 @@ export class LeaderboardApi extends BaseAPI {
* @param {string} productId The Brokerage Product ID provided by GRL.
* @param {LeaderboardCode} boardCode The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts
* @param {LeaderboardFrequency} freq The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00
- * @param {string} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
+ * @param {string | null} [countryIso] Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.
* @param {string} [bpuid] Brokerage Product User ID. If passed, this results in the filtering of rows to include this user\&#39;s row, plus rows above and below in rank (up to &#x60;limit&#x60; rows). Otherwise, the top &#x60;limit&#x60; rows are returned.
* @param {string} [withinTime] Any local timestamp falling within the desired leaderboard\&#39;s period. If not passed, uses the country\&#39;s current time period.
* @param {number} [limit] Max number of rows to return
@@ -9461,7 +9619,7 @@ export class LeaderboardApi extends BaseAPI {
* @throws {RequiredError}
* @memberof LeaderboardApi
*/
- public timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string, bpuid?: string, withinTime?: string, limit?: number, options?: RawAxiosRequestConfig) {
+ public timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId: string, boardCode: LeaderboardCode, freq: LeaderboardFrequency, countryIso?: string | null, bpuid?: string, withinTime?: string, limit?: number, options?: RawAxiosRequestConfig) {
return LeaderboardApiFp(this.configuration).timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(productId, boardCode, freq, countryIso, bpuid, withinTime, limit, options).then((request) => request(this.axios, this.basePath));
}
}
@@ -9926,168 +10084,6 @@ export const OfferwallApiAxiosParamCreator = function (configuration?: Configura
};
},
/**
- * Only returns a single bucket with the top scoring tasks.
- * @summary Single Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- singleOfferwallProductIdOfferwall5fl8bpv5Get: async (productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, minBinSize?: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
- // verify required parameter 'productId' is not null or undefined
- assertParamExists('singleOfferwallProductIdOfferwall5fl8bpv5Get', 'productId', productId)
- // verify required parameter 'bpuid' is not null or undefined
- assertParamExists('singleOfferwallProductIdOfferwall5fl8bpv5Get', 'bpuid', bpuid)
- const localVarPath = `/{product_id}/offerwall/5fl8bpv5/`
- .replace(`{${"product_id"}}`, encodeURIComponent(String(productId)));
- // use dummy base URL string because the URL constructor only accepts absolute URLs.
- const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
- let baseOptions;
- if (configuration) {
- baseOptions = configuration.baseOptions;
- }
-
- const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
- const localVarHeaderParameter = {} as any;
- const localVarQueryParameter = {} as any;
-
- if (bpuid !== undefined) {
- localVarQueryParameter['bpuid'] = bpuid;
- }
-
- if (ip !== undefined) {
- localVarQueryParameter['ip'] = ip;
- }
-
- if (countryIso !== undefined) {
- localVarQueryParameter['country_iso'] = countryIso;
- }
-
- if (languages) {
- localVarQueryParameter['languages'] = languages;
- }
-
- if (behavior !== undefined) {
- localVarQueryParameter['behavior'] = behavior;
- }
-
- if (minPayout !== undefined) {
- localVarQueryParameter['min_payout'] = minPayout;
- }
-
- if (duration !== undefined) {
- localVarQueryParameter['duration'] = duration;
- }
-
- if (minBinSize !== undefined) {
- localVarQueryParameter['min_bin_size'] = minBinSize;
- }
-
-
-
- setSearchParams(localVarUrlObj, localVarQueryParameter);
- let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
- localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
-
- return {
- url: toPathString(localVarUrlObj),
- options: localVarRequestOptions,
- };
- },
- /**
- * Returns an offerwall with buckets that are clustered by setting as seeds the highest scoring surveys for each bin, then the rest are distributed according to their Euclidean distance using the bucket\'s features.
- * @summary Starwall Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- starwallOfferwallProductIdOfferwallB59a2d2bGet: async (productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
- // verify required parameter 'productId' is not null or undefined
- assertParamExists('starwallOfferwallProductIdOfferwallB59a2d2bGet', 'productId', productId)
- // verify required parameter 'bpuid' is not null or undefined
- assertParamExists('starwallOfferwallProductIdOfferwallB59a2d2bGet', 'bpuid', bpuid)
- const localVarPath = `/{product_id}/offerwall/b59a2d2b/`
- .replace(`{${"product_id"}}`, encodeURIComponent(String(productId)));
- // use dummy base URL string because the URL constructor only accepts absolute URLs.
- const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
- let baseOptions;
- if (configuration) {
- baseOptions = configuration.baseOptions;
- }
-
- const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
- const localVarHeaderParameter = {} as any;
- const localVarQueryParameter = {} as any;
-
- if (bpuid !== undefined) {
- localVarQueryParameter['bpuid'] = bpuid;
- }
-
- if (ip !== undefined) {
- localVarQueryParameter['ip'] = ip;
- }
-
- if (countryIso !== undefined) {
- localVarQueryParameter['country_iso'] = countryIso;
- }
-
- if (languages) {
- localVarQueryParameter['languages'] = languages;
- }
-
- if (behavior !== undefined) {
- localVarQueryParameter['behavior'] = behavior;
- }
-
- if (minPayout !== undefined) {
- localVarQueryParameter['min_payout'] = minPayout;
- }
-
- if (duration !== undefined) {
- localVarQueryParameter['duration'] = duration;
- }
-
- if (nBins !== undefined) {
- localVarQueryParameter['n_bins'] = nBins;
- }
-
- if (minBinSize !== undefined) {
- localVarQueryParameter['min_bin_size'] = minBinSize;
- }
-
- if (splitBy !== undefined) {
- localVarQueryParameter['split_by'] = splitBy;
- }
-
-
-
- setSearchParams(localVarUrlObj, localVarQueryParameter);
- let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
- localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
-
- return {
- url: toPathString(localVarUrlObj),
- options: localVarRequestOptions,
- };
- },
- /**
* Same as the StarwallOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Starwall Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -10346,92 +10342,6 @@ export const OfferwallApiAxiosParamCreator = function (configuration?: Configura
};
},
/**
- * Returns an offerwall with buckets that are clustered by the `split_by` argument using KMeans clustering.
- * @summary Topn Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- topNOfferwallProductIdOfferwall45b7228a7Get: async (productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
- // verify required parameter 'productId' is not null or undefined
- assertParamExists('topNOfferwallProductIdOfferwall45b7228a7Get', 'productId', productId)
- // verify required parameter 'bpuid' is not null or undefined
- assertParamExists('topNOfferwallProductIdOfferwall45b7228a7Get', 'bpuid', bpuid)
- const localVarPath = `/{product_id}/offerwall/45b7228a7/`
- .replace(`{${"product_id"}}`, encodeURIComponent(String(productId)));
- // use dummy base URL string because the URL constructor only accepts absolute URLs.
- const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
- let baseOptions;
- if (configuration) {
- baseOptions = configuration.baseOptions;
- }
-
- const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
- const localVarHeaderParameter = {} as any;
- const localVarQueryParameter = {} as any;
-
- if (bpuid !== undefined) {
- localVarQueryParameter['bpuid'] = bpuid;
- }
-
- if (ip !== undefined) {
- localVarQueryParameter['ip'] = ip;
- }
-
- if (countryIso !== undefined) {
- localVarQueryParameter['country_iso'] = countryIso;
- }
-
- if (languages) {
- localVarQueryParameter['languages'] = languages;
- }
-
- if (behavior !== undefined) {
- localVarQueryParameter['behavior'] = behavior;
- }
-
- if (minPayout !== undefined) {
- localVarQueryParameter['min_payout'] = minPayout;
- }
-
- if (duration !== undefined) {
- localVarQueryParameter['duration'] = duration;
- }
-
- if (nBins !== undefined) {
- localVarQueryParameter['n_bins'] = nBins;
- }
-
- if (minBinSize !== undefined) {
- localVarQueryParameter['min_bin_size'] = minBinSize;
- }
-
- if (splitBy !== undefined) {
- localVarQueryParameter['split_by'] = splitBy;
- }
-
-
-
- setSearchParams(localVarUrlObj, localVarQueryParameter);
- let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
- localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
-
- return {
- url: toPathString(localVarUrlObj),
- options: localVarRequestOptions,
- };
- },
- /**
* Same as the TopNOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Topn Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -10901,50 +10811,6 @@ export const OfferwallApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
- * Only returns a single bucket with the top scoring tasks.
- * @summary Single Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- async singleOfferwallProductIdOfferwall5fl8bpv5Get(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, minBinSize?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<SingleEntryOfferWallResponse>> {
- const localVarAxiosArgs = await localVarAxiosParamCreator.singleOfferwallProductIdOfferwall5fl8bpv5Get(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, minBinSize, options);
- const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
- const localVarOperationServerBasePath = operationServerMap['OfferwallApi.singleOfferwallProductIdOfferwall5fl8bpv5Get']?.[localVarOperationServerIndex]?.url;
- return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
- },
- /**
- * Returns an offerwall with buckets that are clustered by setting as seeds the highest scoring surveys for each bin, then the rest are distributed according to their Euclidean distance using the bucket\'s features.
- * @summary Starwall Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- async starwallOfferwallProductIdOfferwallB59a2d2bGet(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<StarwallOfferWallResponse>> {
- const localVarAxiosArgs = await localVarAxiosParamCreator.starwallOfferwallProductIdOfferwallB59a2d2bGet(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, minBinSize, splitBy, options);
- const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
- const localVarOperationServerBasePath = operationServerMap['OfferwallApi.starwallOfferwallProductIdOfferwallB59a2d2bGet']?.[localVarOperationServerIndex]?.url;
- return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
- },
- /**
* Same as the StarwallOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Starwall Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -11014,29 +10880,6 @@ export const OfferwallApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
- * Returns an offerwall with buckets that are clustered by the `split_by` argument using KMeans clustering.
- * @summary Topn Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- async topNOfferwallProductIdOfferwall45b7228a7Get(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<TopNOfferWallResponse>> {
- const localVarAxiosArgs = await localVarAxiosParamCreator.topNOfferwallProductIdOfferwall45b7228a7Get(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, minBinSize, splitBy, options);
- const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
- const localVarOperationServerBasePath = operationServerMap['OfferwallApi.topNOfferwallProductIdOfferwall45b7228a7Get']?.[localVarOperationServerIndex]?.url;
- return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
- },
- /**
* Same as the TopNOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Topn Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -11244,44 +11087,6 @@ export const OfferwallApiFactory = function (configuration?: Configuration, base
return localVarFp.oneShotOfferwallProductIdOfferwall6f27b1aeGet(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, sources, options).then((request) => request(axios, basePath));
},
/**
- * Only returns a single bucket with the top scoring tasks.
- * @summary Single Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- singleOfferwallProductIdOfferwall5fl8bpv5Get(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, minBinSize?: number, options?: RawAxiosRequestConfig): AxiosPromise<SingleEntryOfferWallResponse> {
- return localVarFp.singleOfferwallProductIdOfferwall5fl8bpv5Get(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, minBinSize, options).then((request) => request(axios, basePath));
- },
- /**
- * Returns an offerwall with buckets that are clustered by setting as seeds the highest scoring surveys for each bin, then the rest are distributed according to their Euclidean distance using the bucket\'s features.
- * @summary Starwall Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- starwallOfferwallProductIdOfferwallB59a2d2bGet(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum, options?: RawAxiosRequestConfig): AxiosPromise<StarwallOfferWallResponse> {
- return localVarFp.starwallOfferwallProductIdOfferwallB59a2d2bGet(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, minBinSize, splitBy, options).then((request) => request(axios, basePath));
- },
- /**
* Same as the StarwallOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Starwall Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -11342,26 +11147,6 @@ export const OfferwallApiFactory = function (configuration?: Configuration, base
return localVarFp.starwallPlusOfferwallProductIdOfferwall5481f322Get(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, minBinSize, splitBy, options).then((request) => request(axios, basePath));
},
/**
- * Returns an offerwall with buckets that are clustered by the `split_by` argument using KMeans clustering.
- * @summary Topn Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- topNOfferwallProductIdOfferwall45b7228a7Get(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum, options?: RawAxiosRequestConfig): AxiosPromise<TopNOfferWallResponse> {
- return localVarFp.topNOfferwallProductIdOfferwall45b7228a7Get(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, minBinSize, splitBy, options).then((request) => request(axios, basePath));
- },
- /**
* Same as the TopNOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Topn Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -11569,48 +11354,6 @@ export class OfferwallApi extends BaseAPI {
}
/**
- * Only returns a single bucket with the top scoring tasks.
- * @summary Single Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- * @memberof OfferwallApi
- */
- public singleOfferwallProductIdOfferwall5fl8bpv5Get(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, minBinSize?: number, options?: RawAxiosRequestConfig) {
- return OfferwallApiFp(this.configuration).singleOfferwallProductIdOfferwall5fl8bpv5Get(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, minBinSize, options).then((request) => request(this.axios, this.basePath));
- }
-
- /**
- * Returns an offerwall with buckets that are clustered by setting as seeds the highest scoring surveys for each bin, then the rest are distributed according to their Euclidean distance using the bucket\'s features.
- * @summary Starwall Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- * @memberof OfferwallApi
- */
- public starwallOfferwallProductIdOfferwallB59a2d2bGet(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum, options?: RawAxiosRequestConfig) {
- return OfferwallApiFp(this.configuration).starwallOfferwallProductIdOfferwallB59a2d2bGet(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, minBinSize, splitBy, options).then((request) => request(this.axios, this.basePath));
- }
-
- /**
* Same as the StarwallOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Starwall Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -11677,28 +11420,6 @@ export class OfferwallApi extends BaseAPI {
}
/**
- * Returns an offerwall with buckets that are clustered by the `split_by` argument using KMeans clustering.
- * @summary Topn Offerwall
- * @param {string} productId The Brokerage Product ID provided by GRL.
- * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
- * @param {string} [ip] Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided.
- * @param {string} [countryIso] Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase)
- * @param {Array<string>} [languages] Respondent\&#39;s desired languages (ISO 639-2/B, lowercase)
- * @param {string} [behavior] Allows using custom scoring functions. Please discuss directly with GRL.
- * @param {string} [minPayout] Decimal representation of the minimum amount of USD that any of the tasks will pay
- * @param {number} [duration] Maximum length of desired task (in seconds).
- * @param {number} [nBins] Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.
- * @param {number} [minBinSize] Minimum number of tasks that need to be in a bucket
- * @param {TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum} [splitBy] Cluster tasks by payout or duration
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- * @memberof OfferwallApi
- */
- public topNOfferwallProductIdOfferwall45b7228a7Get(productId: string, bpuid: string, ip?: string, countryIso?: string, languages?: Array<string>, behavior?: string, minPayout?: string, duration?: number, nBins?: number, minBinSize?: number, splitBy?: TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum, options?: RawAxiosRequestConfig) {
- return OfferwallApiFp(this.configuration).topNOfferwallProductIdOfferwall45b7228a7Get(productId, bpuid, ip, countryIso, languages, behavior, minPayout, duration, nBins, minBinSize, splitBy, options).then((request) => request(this.axios, this.basePath));
- }
-
- /**
* Same as the TopNOfferWall, but the buckets include contents and no buckets are returned if the user is blocked.
* @summary Topn Plus Block Offerwall
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -11788,14 +11509,6 @@ export class OfferwallApi extends BaseAPI {
/**
* @export
*/
-export const StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum = {
- Payout: 'payout',
- Duration: 'duration'
-} as const;
-export type StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum = typeof StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum[keyof typeof StarwallOfferwallProductIdOfferwallB59a2d2bGetSplitByEnum];
-/**
- * @export
- */
export const StarwallPlusBlockOfferwallProductIdOfferwall7fa1b3f4GetSplitByEnum = {
Payout: 'payout',
Duration: 'duration'
@@ -11820,14 +11533,6 @@ export type StarwallPlusOfferwallProductIdOfferwall5481f322GetSplitByEnum = type
/**
* @export
*/
-export const TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum = {
- Payout: 'payout',
- Duration: 'duration'
-} as const;
-export type TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum = typeof TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum[keyof typeof TopNOfferwallProductIdOfferwall45b7228a7GetSplitByEnum];
-/**
- * @export
- */
export const TopNPlusBlockOfferwallProductIdOfferwallD48cce47GetSplitByEnum = {
Payout: 'payout',
Duration: 'duration'
@@ -13149,12 +12854,162 @@ export class StreamsApi extends BaseAPI {
/**
+ * THLApi - axios parameter creator
+ * @export
+ */
+export const THLApiAxiosParamCreator = function (configuration?: Configuration) {
+ return {
+ /**
+ *
+ * @summary Manage Cashout
+ * @param {ManageCashoutBody} manageCashoutBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ manageCashoutThlManageCashoutPost: async (manageCashoutBody: ManageCashoutBody, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
+ // verify required parameter 'manageCashoutBody' is not null or undefined
+ assertParamExists('manageCashoutThlManageCashoutPost', 'manageCashoutBody', manageCashoutBody)
+ const localVarPath = `/thl/manage_cashout/`;
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
+ let baseOptions;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+
+
+ localVarHeaderParameter['Content-Type'] = 'application/json';
+
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+ localVarRequestOptions.data = serializeDataIfNeeded(manageCashoutBody, localVarRequestOptions, configuration)
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
+ }
+};
+
+/**
+ * THLApi - functional programming interface
+ * @export
+ */
+export const THLApiFp = function(configuration?: Configuration) {
+ const localVarAxiosParamCreator = THLApiAxiosParamCreator(configuration)
+ return {
+ /**
+ *
+ * @summary Manage Cashout
+ * @param {ManageCashoutBody} manageCashoutBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async manageCashoutThlManageCashoutPost(manageCashoutBody: ManageCashoutBody, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<UserPayoutEvent>> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.manageCashoutThlManageCashoutPost(manageCashoutBody, options);
+ const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
+ const localVarOperationServerBasePath = operationServerMap['THLApi.manageCashoutThlManageCashoutPost']?.[localVarOperationServerIndex]?.url;
+ return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
+ },
+ }
+};
+
+/**
+ * THLApi - factory interface
+ * @export
+ */
+export const THLApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
+ const localVarFp = THLApiFp(configuration)
+ return {
+ /**
+ *
+ * @summary Manage Cashout
+ * @param {ManageCashoutBody} manageCashoutBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ manageCashoutThlManageCashoutPost(manageCashoutBody: ManageCashoutBody, options?: RawAxiosRequestConfig): AxiosPromise<UserPayoutEvent> {
+ return localVarFp.manageCashoutThlManageCashoutPost(manageCashoutBody, options).then((request) => request(axios, basePath));
+ },
+ };
+};
+
+/**
+ * THLApi - object-oriented interface
+ * @export
+ * @class THLApi
+ * @extends {BaseAPI}
+ */
+export class THLApi extends BaseAPI {
+ /**
+ *
+ * @summary Manage Cashout
+ * @param {ManageCashoutBody} manageCashoutBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof THLApi
+ */
+ public manageCashoutThlManageCashoutPost(manageCashoutBody: ManageCashoutBody, options?: RawAxiosRequestConfig) {
+ return THLApiFp(this.configuration).manageCashoutThlManageCashoutPost(manageCashoutBody, options).then((request) => request(this.axios, this.basePath));
+ }
+}
+
+
+
+/**
* WalletApi - axios parameter creator
* @export
*/
export const WalletApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
+ * Attempt to claim an Attempt Credit from the user\'s latest Session.
+ * @summary Claim Latest Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {AttemptCreditClaimBody} attemptCreditClaimBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ claimLatestAttemptCreditProductIdWalletAttemptCreditPost: async (productId: string, attemptCreditClaimBody: AttemptCreditClaimBody, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
+ // verify required parameter 'productId' is not null or undefined
+ assertParamExists('claimLatestAttemptCreditProductIdWalletAttemptCreditPost', 'productId', productId)
+ // verify required parameter 'attemptCreditClaimBody' is not null or undefined
+ assertParamExists('claimLatestAttemptCreditProductIdWalletAttemptCreditPost', 'attemptCreditClaimBody', attemptCreditClaimBody)
+ const localVarPath = `/{product_id}/wallet/attempt-credit/`
+ .replace(`{${"product_id"}}`, encodeURIComponent(String(productId)));
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
+ let baseOptions;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+
+
+ localVarHeaderParameter['Content-Type'] = 'application/json';
+
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+ localVarRequestOptions.data = serializeDataIfNeeded(attemptCreditClaimBody, localVarRequestOptions, configuration)
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
+ /**
* A user can only have 1 unique Cashout Method of any type at a time (eg. they can\'t create multiple paypal payout methods). Cashout Methods cannot be edited, they can only be created or deleted. Creating different Cashout Methods will require type-dependent request data attributes in order to be successfully created. Currently only creating paypal or Cash in Mail cashout methods are supported
* @summary Create Cashout Method
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13240,6 +13095,44 @@ export const WalletApiAxiosParamCreator = function (configuration?: Configuratio
};
},
/**
+ * Get an Attempt Credit by a user\'s Session.
+ * @summary Get Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} tsid A unique identifier for the session
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ getAttemptCreditProductIdWalletAttemptCreditTsidGet: async (productId: string, tsid: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
+ // verify required parameter 'productId' is not null or undefined
+ assertParamExists('getAttemptCreditProductIdWalletAttemptCreditTsidGet', 'productId', productId)
+ // verify required parameter 'tsid' is not null or undefined
+ assertParamExists('getAttemptCreditProductIdWalletAttemptCreditTsidGet', 'tsid', tsid)
+ const localVarPath = `/{product_id}/wallet/attempt-credit/{tsid}/`
+ .replace(`{${"product_id"}}`, encodeURIComponent(String(productId)))
+ .replace(`{${"tsid"}}`, encodeURIComponent(String(tsid)));
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
+ let baseOptions;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+
+
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
+ /**
* Retrieve the details for a specific Cashout event
* @summary Get Cashout Detail
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13475,6 +13368,47 @@ export const WalletApiAxiosParamCreator = function (configuration?: Configuratio
};
},
/**
+ * Retrieve a respondent\'s wallets and balances for display
+ * @summary Get User Wallets
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ getUserWalletsProductIdWalletsGet: async (productId: string, bpuid: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
+ // verify required parameter 'productId' is not null or undefined
+ assertParamExists('getUserWalletsProductIdWalletsGet', 'productId', productId)
+ // verify required parameter 'bpuid' is not null or undefined
+ assertParamExists('getUserWalletsProductIdWalletsGet', 'bpuid', bpuid)
+ const localVarPath = `/{product_id}/wallets/`
+ .replace(`{${"product_id"}}`, encodeURIComponent(String(productId)));
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
+ let baseOptions;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+ if (bpuid !== undefined) {
+ localVarQueryParameter['bpuid'] = bpuid;
+ }
+
+
+
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
+ /**
* Request a cashout taken from a user\'s available wallet balance, to be paid via a particular cashout method.
* @summary Submit User Cashout
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13525,6 +13459,20 @@ export const WalletApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = WalletApiAxiosParamCreator(configuration)
return {
/**
+ * Attempt to claim an Attempt Credit from the user\'s latest Session.
+ * @summary Claim Latest Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {AttemptCreditClaimBody} attemptCreditClaimBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async claimLatestAttemptCreditProductIdWalletAttemptCreditPost(productId: string, attemptCreditClaimBody: AttemptCreditClaimBody, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AttemptCreditClaimResponse>> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.claimLatestAttemptCreditProductIdWalletAttemptCreditPost(productId, attemptCreditClaimBody, options);
+ const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
+ const localVarOperationServerBasePath = operationServerMap['WalletApi.claimLatestAttemptCreditProductIdWalletAttemptCreditPost']?.[localVarOperationServerIndex]?.url;
+ return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
+ },
+ /**
* A user can only have 1 unique Cashout Method of any type at a time (eg. they can\'t create multiple paypal payout methods). Cashout Methods cannot be edited, they can only be created or deleted. Creating different Cashout Methods will require type-dependent request data attributes in order to be successfully created. Currently only creating paypal or Cash in Mail cashout methods are supported
* @summary Create Cashout Method
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13554,6 +13502,20 @@ export const WalletApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
+ * Get an Attempt Credit by a user\'s Session.
+ * @summary Get Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} tsid A unique identifier for the session
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async getAttemptCreditProductIdWalletAttemptCreditTsidGet(productId: string, tsid: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AttemptCreditClaimResponse>> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.getAttemptCreditProductIdWalletAttemptCreditTsidGet(productId, tsid, options);
+ const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
+ const localVarOperationServerBasePath = operationServerMap['WalletApi.getAttemptCreditProductIdWalletAttemptCreditTsidGet']?.[localVarOperationServerIndex]?.url;
+ return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
+ },
+ /**
* Retrieve the details for a specific Cashout event
* @summary Get Cashout Detail
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13630,6 +13592,20 @@ export const WalletApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
+ * Retrieve a respondent\'s wallets and balances for display
+ * @summary Get User Wallets
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async getUserWalletsProductIdWalletsGet(productId: string, bpuid: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<UserLedgerWallets>> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.getUserWalletsProductIdWalletsGet(productId, bpuid, options);
+ const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
+ const localVarOperationServerBasePath = operationServerMap['WalletApi.getUserWalletsProductIdWalletsGet']?.[localVarOperationServerIndex]?.url;
+ return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
+ },
+ /**
* Request a cashout taken from a user\'s available wallet balance, to be paid via a particular cashout method.
* @summary Submit User Cashout
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13654,6 +13630,17 @@ export const WalletApiFactory = function (configuration?: Configuration, basePat
const localVarFp = WalletApiFp(configuration)
return {
/**
+ * Attempt to claim an Attempt Credit from the user\'s latest Session.
+ * @summary Claim Latest Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {AttemptCreditClaimBody} attemptCreditClaimBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ claimLatestAttemptCreditProductIdWalletAttemptCreditPost(productId: string, attemptCreditClaimBody: AttemptCreditClaimBody, options?: RawAxiosRequestConfig): AxiosPromise<AttemptCreditClaimResponse> {
+ return localVarFp.claimLatestAttemptCreditProductIdWalletAttemptCreditPost(productId, attemptCreditClaimBody, options).then((request) => request(axios, basePath));
+ },
+ /**
* A user can only have 1 unique Cashout Method of any type at a time (eg. they can\'t create multiple paypal payout methods). Cashout Methods cannot be edited, they can only be created or deleted. Creating different Cashout Methods will require type-dependent request data attributes in order to be successfully created. Currently only creating paypal or Cash in Mail cashout methods are supported
* @summary Create Cashout Method
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13677,6 +13664,17 @@ export const WalletApiFactory = function (configuration?: Configuration, basePat
return localVarFp.deleteCashoutMethodProductIdCashoutMethodsCashoutMethodIdDelete(productId, cashoutMethodId, bpuid, options).then((request) => request(axios, basePath));
},
/**
+ * Get an Attempt Credit by a user\'s Session.
+ * @summary Get Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} tsid A unique identifier for the session
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ getAttemptCreditProductIdWalletAttemptCreditTsidGet(productId: string, tsid: string, options?: RawAxiosRequestConfig): AxiosPromise<AttemptCreditClaimResponse> {
+ return localVarFp.getAttemptCreditProductIdWalletAttemptCreditTsidGet(productId, tsid, options).then((request) => request(axios, basePath));
+ },
+ /**
* Retrieve the details for a specific Cashout event
* @summary Get Cashout Detail
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13738,6 +13736,17 @@ export const WalletApiFactory = function (configuration?: Configuration, basePat
return localVarFp.getUserWalletBalanceProductIdWalletGet(productId, bpuid, options).then((request) => request(axios, basePath));
},
/**
+ * Retrieve a respondent\'s wallets and balances for display
+ * @summary Get User Wallets
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ getUserWalletsProductIdWalletsGet(productId: string, bpuid: string, options?: RawAxiosRequestConfig): AxiosPromise<UserLedgerWallets> {
+ return localVarFp.getUserWalletsProductIdWalletsGet(productId, bpuid, options).then((request) => request(axios, basePath));
+ },
+ /**
* Request a cashout taken from a user\'s available wallet balance, to be paid via a particular cashout method.
* @summary Submit User Cashout
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13759,6 +13768,19 @@ export const WalletApiFactory = function (configuration?: Configuration, basePat
*/
export class WalletApi extends BaseAPI {
/**
+ * Attempt to claim an Attempt Credit from the user\'s latest Session.
+ * @summary Claim Latest Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {AttemptCreditClaimBody} attemptCreditClaimBody
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof WalletApi
+ */
+ public claimLatestAttemptCreditProductIdWalletAttemptCreditPost(productId: string, attemptCreditClaimBody: AttemptCreditClaimBody, options?: RawAxiosRequestConfig) {
+ return WalletApiFp(this.configuration).claimLatestAttemptCreditProductIdWalletAttemptCreditPost(productId, attemptCreditClaimBody, options).then((request) => request(this.axios, this.basePath));
+ }
+
+ /**
* A user can only have 1 unique Cashout Method of any type at a time (eg. they can\'t create multiple paypal payout methods). Cashout Methods cannot be edited, they can only be created or deleted. Creating different Cashout Methods will require type-dependent request data attributes in order to be successfully created. Currently only creating paypal or Cash in Mail cashout methods are supported
* @summary Create Cashout Method
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13786,6 +13808,19 @@ export class WalletApi extends BaseAPI {
}
/**
+ * Get an Attempt Credit by a user\'s Session.
+ * @summary Get Attempt Credit
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} tsid A unique identifier for the session
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof WalletApi
+ */
+ public getAttemptCreditProductIdWalletAttemptCreditTsidGet(productId: string, tsid: string, options?: RawAxiosRequestConfig) {
+ return WalletApiFp(this.configuration).getAttemptCreditProductIdWalletAttemptCreditTsidGet(productId, tsid, options).then((request) => request(this.axios, this.basePath));
+ }
+
+ /**
* Retrieve the details for a specific Cashout event
* @summary Get Cashout Detail
* @param {string} productId The Brokerage Product ID provided by GRL.
@@ -13857,6 +13892,19 @@ export class WalletApi extends BaseAPI {
}
/**
+ * Retrieve a respondent\'s wallets and balances for display
+ * @summary Get User Wallets
+ * @param {string} productId The Brokerage Product ID provided by GRL.
+ * @param {string} bpuid A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof WalletApi
+ */
+ public getUserWalletsProductIdWalletsGet(productId: string, bpuid: string, options?: RawAxiosRequestConfig) {
+ return WalletApiFp(this.configuration).getUserWalletsProductIdWalletsGet(productId, bpuid, options).then((request) => request(this.axios, this.basePath));
+ }
+
+ /**
* Request a cashout taken from a user\'s available wallet balance, to be paid via a particular cashout method.
* @summary Submit User Cashout
* @param {string} productId The Brokerage Product ID provided by GRL.
diff --git a/jb-ui/src/api_fsb/docs/AccessType.md b/jb-ui/src/api_fsb/docs/AccessType.md
new file mode 100644
index 0000000..1e4ea7d
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/AccessType.md
@@ -0,0 +1,19 @@
+# AccessType
+
+How the network is used
+
+## Enum
+
+* `Residential` (value: `'residential'`)
+
+* `Mobile` (value: `'mobile'`)
+
+* `Satellite` (value: `'satellite'`)
+
+* `Datacenter` (value: `'datacenter'`)
+
+* `Enterprise` (value: `'enterprise'`)
+
+* `Unknown` (value: `'unknown'`)
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/AccountType.md b/jb-ui/src/api_fsb/docs/AccountType.md
index 6d2e246..d6ae50d 100644
--- a/jb-ui/src/api_fsb/docs/AccountType.md
+++ b/jb-ui/src/api_fsb/docs/AccountType.md
@@ -9,6 +9,8 @@
* `UserWallet` (value: `'user_wallet'`)
+* `UserAttemptCredit` (value: `'user_attempt_credit'`)
+
* `Cash` (value: `'cash'`)
* `Revenue` (value: `'revenue'`)
diff --git a/jb-ui/src/api_fsb/docs/Amount.md b/jb-ui/src/api_fsb/docs/Amount.md
new file mode 100644
index 0000000..ace69cb
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/Amount.md
@@ -0,0 +1,19 @@
+# Amount
+
+The amount of the entry in integer counts or USD Cents
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+
+## Example
+
+```typescript
+import { Amount } from './api';
+
+const instance: Amount = {
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/AttemptCreditClaimBody.md b/jb-ui/src/api_fsb/docs/AttemptCreditClaimBody.md
new file mode 100644
index 0000000..acf6c7e
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/AttemptCreditClaimBody.md
@@ -0,0 +1,20 @@
+# AttemptCreditClaimBody
+
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**bpuid** | **string** | (product_user_id) The user requesting the claim | [default to undefined]
+
+## Example
+
+```typescript
+import { AttemptCreditClaimBody } from './api';
+
+const instance: AttemptCreditClaimBody = {
+ bpuid,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/AttemptCreditClaimResponse.md b/jb-ui/src/api_fsb/docs/AttemptCreditClaimResponse.md
new file mode 100644
index 0000000..c8d0850
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/AttemptCreditClaimResponse.md
@@ -0,0 +1,20 @@
+# AttemptCreditClaimResponse
+
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**amount** | **number** | | [default to undefined]
+
+## Example
+
+```typescript
+import { AttemptCreditClaimResponse } from './api';
+
+const instance: AttemptCreditClaimResponse = {
+ amount,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/BrokerageProductPayoutEvent.md b/jb-ui/src/api_fsb/docs/BrokerageProductPayoutEvent.md
index c2d2ca6..794932f 100644
--- a/jb-ui/src/api_fsb/docs/BrokerageProductPayoutEvent.md
+++ b/jb-ui/src/api_fsb/docs/BrokerageProductPayoutEvent.md
@@ -7,14 +7,14 @@ The amount - created: When the Brokerage Product was paid out
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**uuid** | **string** | | [optional] [default to undefined]
-**debit_account_uuid** | **string** | The LedgerAccount.uuid that money is being requested from. Thie User or Brokerage Product is retrievable through the LedgerAccount.reference_uuid | [default to undefined]
-**cashout_method_uuid** | **string** | References a row in the account_cashoutmethod table. This is the cashout method that was used to request this payout. (A cashout is the same thing as a payout) | [default to undefined]
+**debit_account_uuid** | **string** | | [default to undefined]
+**cashout_method_uuid** | **string** | | [default to undefined]
**created** | **string** | | [optional] [default to undefined]
**amount** | **number** | The USDCent amount int. This cannot be 0 or negative | [default to undefined]
**status** | [**PayoutStatus**](PayoutStatus.md) | | [optional] [default to undefined]
**ext_ref_id** | **string** | | [optional] [default to undefined]
**payout_type** | [**PayoutType**](PayoutType.md) | - &#x60;PAYPAL&#x60; &#x3D; PAYPAL - &#x60;TANGO&#x60; &#x3D; TANGO - &#x60;DWOLLA&#x60; &#x3D; DWOLLA - &#x60;ACH&#x60; &#x3D; ACH - &#x60;WIRE&#x60; &#x3D; WIRE - &#x60;CASH_IN_MAIL&#x60; &#x3D; CASH_IN_MAIL - &#x60;PRIZE&#x60; &#x3D; PRIZE - &#x60;AMT&#x60; &#x3D; AMT - &#x60;AMT_BONUS&#x60; &#x3D; AMT_BONUS - &#x60;AMT_ASSIGNMENT&#x60; &#x3D; AMT_HIT | [default to undefined]
-**request_data** | **object** | Stores payout-type-specific information that is used to request this payout from the external provider. | [optional] [default to undefined]
+**request_data** | **object** | | [optional] [default to undefined]
**order_data** | [**OrderData**](OrderData.md) | | [optional] [default to undefined]
**product_id** | **string** | The Brokerage Product that was paid out | [default to undefined]
**method** | [**PayoutType**](PayoutType.md) | - &#x60;PAYPAL&#x60; &#x3D; PAYPAL - &#x60;TANGO&#x60; &#x3D; TANGO - &#x60;DWOLLA&#x60; &#x3D; DWOLLA - &#x60;ACH&#x60; &#x3D; ACH - &#x60;WIRE&#x60; &#x3D; WIRE - &#x60;CASH_IN_MAIL&#x60; &#x3D; CASH_IN_MAIL - &#x60;PRIZE&#x60; &#x3D; PRIZE - &#x60;AMT&#x60; &#x3D; AMT - &#x60;AMT_BONUS&#x60; &#x3D; AMT_BONUS - &#x60;AMT_ASSIGNMENT&#x60; &#x3D; AMT_HIT | [readonly] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/CashoutMethodOut.md b/jb-ui/src/api_fsb/docs/CashoutMethodOut.md
index c4e4832..b8c4b94 100644
--- a/jb-ui/src/api_fsb/docs/CashoutMethodOut.md
+++ b/jb-ui/src/api_fsb/docs/CashoutMethodOut.md
@@ -14,7 +14,7 @@ Name | Type | Description | Notes
**max_value** | **number** | (In lowest unit of the original_currency), The maximum amount that can be cashed out in one transaction. | [default to undefined]
**min_value** | **number** | (In lowest unit of the original_currency), The minimum amount that can be cashed out in one transaction. | [default to undefined]
**name** | **string** | A descriptive name for the cashout method. | [default to undefined]
-**type** | [**PayoutType**](PayoutType.md) | The method in which the requested payout is delivered. Allowed values: - __PAYPAL__ *(PAYPAL)*: User is paid out to their personal PayPal email address - __TANGO__ *(TANGO)*: User is paid uut via a Tango Gift Card - __DWOLLA__ *(DWOLLA)*: DWOLLA - __ACH__ *(ACH)*: A payment is made to a bank account using ACH - __WIRE__ *(WIRE)*: A payment is made to a bank account using ACH - __CASH_IN_MAIL__ *(CASH_IN_MAIL)*: A payment is made in cash and mailed to the user. - __PRIZE__ *(PRIZE)*: A payment is made as a prize with some monetary value - __AMT__ *(AMT)*: This is used to designate either AMT_BONUS or AMT_HIT - __AMT_BONUS__ *(AMT_BONUS)*: Amazon Mechanical Turk as a Bonus - __AMT_ASSIGNMENT__ *(AMT_HIT)*: Amazon Mechanical Turk for a HIT | [default to undefined]
+**type** | [**PayoutType**](PayoutType.md) | The method in which the requested payout is delivered. Allowed values: - __PAYPAL__ *(PAYPAL)*: User is paid out to their personal PayPal email address - __TANGO__ *(TANGO)*: User is paid out via a Tango Gift Card - __DWOLLA__ *(DWOLLA)*: DWOLLA - __ACH__ *(ACH)*: A payment is made to a bank account using ACH - __WIRE__ *(WIRE)*: A payment is made to a bank account using ACH - __CASH_IN_MAIL__ *(CASH_IN_MAIL)*: A payment is made in cash and mailed to the user. - __PRIZE__ *(PRIZE)*: A payment is made as a prize with some monetary value - __AMT__ *(AMT)*: This is used to designate either AMT_BONUS or AMT_HIT - __AMT_BONUS__ *(AMT_BONUS)*: Amazon Mechanical Turk as a Bonus - __AMT_ASSIGNMENT__ *(AMT_HIT)*: Amazon Mechanical Turk for a HIT | [default to undefined]
**ext_id** | **string** | | [optional] [default to undefined]
**usd_exchange_rate** | **number** | | [optional] [default to undefined]
**max_value_usd** | **number** | | [optional] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/ContestEntry.md b/jb-ui/src/api_fsb/docs/ContestEntry.md
new file mode 100644
index 0000000..a83f01f
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/ContestEntry.md
@@ -0,0 +1,32 @@
+# ContestEntry
+
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**uuid** | **string** | | [optional] [default to undefined]
+**created_at** | **string** | | [optional] [default to undefined]
+**updated_at** | **string** | | [optional] [default to undefined]
+**entry_type** | [**ContestEntryType**](ContestEntryType.md) | | [default to undefined]
+**amount** | [**Amount**](Amount.md) | | [default to undefined]
+**amount_str** | **string** | | [readonly] [default to undefined]
+**censored_product_user_id** | **string** | | [readonly] [default to undefined]
+
+## Example
+
+```typescript
+import { ContestEntry } from './api';
+
+const instance: ContestEntry = {
+ uuid,
+ created_at,
+ updated_at,
+ entry_type,
+ amount,
+ amount_str,
+ censored_product_user_id,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/ContestEntryType.md b/jb-ui/src/api_fsb/docs/ContestEntryType.md
new file mode 100644
index 0000000..933920b
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/ContestEntryType.md
@@ -0,0 +1,11 @@
+# ContestEntryType
+
+All entries into a contest must be of the same type, and match the entry_type of the Contest itself.
+
+## Enum
+
+* `Count` (value: `'count'`)
+
+* `Cash` (value: `'cash'`)
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/GeoIPInformation.md b/jb-ui/src/api_fsb/docs/GeoIPInformation.md
index 5df598e..2066626 100644
--- a/jb-ui/src/api_fsb/docs/GeoIPInformation.md
+++ b/jb-ui/src/api_fsb/docs/GeoIPInformation.md
@@ -36,7 +36,7 @@ Name | Type | Description | Notes
**network** | **string** | | [optional] [default to undefined]
**organization** | **string** | | [optional] [default to undefined]
**static_ip_score** | **number** | | [optional] [default to undefined]
-**user_type** | [**UserType**](UserType.md) | | [optional] [default to undefined]
+**user_type** | [**AccessType**](AccessType.md) | | [optional] [default to undefined]
**postal_code** | **string** | | [optional] [default to undefined]
**latitude** | **number** | | [optional] [default to undefined]
**longitude** | **number** | | [optional] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/Leaderboard.md b/jb-ui/src/api_fsb/docs/Leaderboard.md
index adae56c..a735f49 100644
--- a/jb-ui/src/api_fsb/docs/Leaderboard.md
+++ b/jb-ui/src/api_fsb/docs/Leaderboard.md
@@ -6,18 +6,18 @@ A leaderboard exists independently for each product_id in each country. Each cou
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
-**id** | **string** | Unique ID for this leaderboard | [optional] [default to undefined]
-**name** | **string** | Descriptive name for the leaderboard based on the board_code | [optional] [default to undefined]
+**id** | **string** | | [optional] [default to undefined]
+**name** | **string** | | [optional] [default to undefined]
**board_code** | [**LeaderboardCode**](LeaderboardCode.md) | The type of leaderboard. What the \&quot;values\&quot; represent. Allowed values: - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts | [default to undefined]
**bpid** | **string** | product_id | [default to undefined]
**country_iso** | **string** | The country this leaderboard is for. | [default to undefined]
**freq** | [**LeaderboardFrequency**](LeaderboardFrequency.md) | The time period range for the leaderboard. Allowed values: - __daily__ *(DAILY)*: UTC midnight to UTC midnight - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC - __monthly__ *(MONTHLY)*: Jan 1 00:00:00 | [default to undefined]
-**timezone_name** | **string** | The timezone for the requested country | [optional] [default to undefined]
+**timezone_name** | **string** | | [optional] [default to undefined]
**sort_order** | **string** | | [optional] [default to SortOrderEnum_Descending]
**row_count** | **number** | The total number of rows in the leaderboard. | [default to undefined]
**rows** | [**Array&lt;LeaderboardRow&gt;**](LeaderboardRow.md) | | [optional] [default to undefined]
**period_start_local** | **string** | The start of the time period covered by this board in local time, tz-aware | [default to undefined]
-**period_end_local** | **string** | The end of the time period covered by this board in local time, tz-aware | [optional] [default to undefined]
+**period_end_local** | **string** | | [optional] [default to undefined]
**start_timestamp** | **number** | (unix timestamp) The start time of the time range this leaderboard covers. | [readonly] [default to undefined]
**end_timestamp** | **number** | (unix timestamp) The end time of the time range this leaderboard covers. | [readonly] [default to undefined]
**utc_offset** | **string** | The UTC offset for the timezone | [readonly] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/LeaderboardRow.md b/jb-ui/src/api_fsb/docs/LeaderboardRow.md
index 23ad7ab..0313f07 100644
--- a/jb-ui/src/api_fsb/docs/LeaderboardRow.md
+++ b/jb-ui/src/api_fsb/docs/LeaderboardRow.md
@@ -8,6 +8,7 @@ Name | Type | Description | Notes
**bpuid** | **string** | product_user_id | [default to undefined]
**rank** | **number** | The numerical data ranks (1 through n) of the values. Ties are ranked using the lowest rank in the group. | [default to undefined]
**value** | **number** | The value. The meaning of the value is dependent on the LeaderboardCode. | [default to undefined]
+**display_name** | **string** | | [optional] [default to undefined]
## Example
@@ -18,6 +19,7 @@ const instance: LeaderboardRow = {
bpuid,
rank,
value,
+ display_name,
};
```
diff --git a/jb-ui/src/api_fsb/docs/LedgerAccount.md b/jb-ui/src/api_fsb/docs/LedgerAccount.md
index f9b1ffa..29caaba 100644
--- a/jb-ui/src/api_fsb/docs/LedgerAccount.md
+++ b/jb-ui/src/api_fsb/docs/LedgerAccount.md
@@ -8,7 +8,7 @@ Name | Type | Description | Notes
**uuid** | **string** | A unique identifier for this Ledger Account | [optional] [default to undefined]
**display_name** | **string** | Human-readable description of the Ledger Account | [default to undefined]
**qualified_name** | **string** | | [default to undefined]
-**account_type** | [**AccountType**](AccountType.md) | - &#x60;bp_commission&#x60; &#x3D; BP_COMMISSION - &#x60;bp_wallet&#x60; &#x3D; BP_WALLET - &#x60;user_wallet&#x60; &#x3D; USER_WALLET - &#x60;cash&#x60; &#x3D; CASH - &#x60;revenue&#x60; &#x3D; REVENUE - &#x60;expense&#x60; &#x3D; EXPENSE - &#x60;contest_wallet&#x60; &#x3D; CONTEST_WALLET - &#x60;credit_line&#x60; &#x3D; CREDIT_LINE - &#x60;wa_wallet&#x60; &#x3D; WA_WALLET - &#x60;wa_budget_pool&#x60; &#x3D; WA_BUDGET_POOL - &#x60;wa_held&#x60; &#x3D; WA_HELD - &#x60;wa_credit_line&#x60; &#x3D; WA_CREDIT_LINE | [default to undefined]
+**account_type** | [**AccountType**](AccountType.md) | - &#x60;bp_commission&#x60; &#x3D; BP_COMMISSION - &#x60;bp_wallet&#x60; &#x3D; BP_WALLET - &#x60;user_wallet&#x60; &#x3D; USER_WALLET - &#x60;user_attempt_credit&#x60; &#x3D; USER_ATTEMPT_CREDIT - &#x60;cash&#x60; &#x3D; CASH - &#x60;revenue&#x60; &#x3D; REVENUE - &#x60;expense&#x60; &#x3D; EXPENSE - &#x60;contest_wallet&#x60; &#x3D; CONTEST_WALLET - &#x60;credit_line&#x60; &#x3D; CREDIT_LINE - &#x60;wa_wallet&#x60; &#x3D; WA_WALLET - &#x60;wa_budget_pool&#x60; &#x3D; WA_BUDGET_POOL - &#x60;wa_held&#x60; &#x3D; WA_HELD - &#x60;wa_credit_line&#x60; &#x3D; WA_CREDIT_LINE | [default to undefined]
**normal_balance** | [**Direction**](Direction.md) | - &#x60;-1&#x60; &#x3D; CREDIT - &#x60;1&#x60; &#x3D; DEBIT | [default to undefined]
**reference_type** | **string** | | [optional] [default to undefined]
**reference_uuid** | **string** | | [optional] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/ManageCashoutBody.md b/jb-ui/src/api_fsb/docs/ManageCashoutBody.md
new file mode 100644
index 0000000..61fdcb2
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/ManageCashoutBody.md
@@ -0,0 +1,22 @@
+# ManageCashoutBody
+
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**payout_id** | **string** | | [default to undefined]
+**new_status** | [**PayoutStatus**](PayoutStatus.md) | | [default to undefined]
+
+## Example
+
+```typescript
+import { ManageCashoutBody } from './api';
+
+const instance: ManageCashoutBody = {
+ payout_id,
+ new_status,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/OfferwallApi.md b/jb-ui/src/api_fsb/docs/OfferwallApi.md
index 8e7591d..4b77589 100644
--- a/jb-ui/src/api_fsb/docs/OfferwallApi.md
+++ b/jb-ui/src/api_fsb/docs/OfferwallApi.md
@@ -10,12 +10,9 @@ All URIs are relative to *https://fsb.generalresearch.com*
|[**offerwallSoftpairPostProductIdOfferwall37d1da64OfferwallIdPost**](#offerwallsoftpairpostproductidofferwall37d1da64offerwallidpost) | **POST** /{product_id}/offerwall/37d1da64/{offerwall_id}/ | Offerwall Softpair Post|
|[**offerwallSoftpairProductIdOfferwall37d1da64Get**](#offerwallsoftpairproductidofferwall37d1da64get) | **GET** /{product_id}/offerwall/37d1da64/ | Offerwall Softpair|
|[**oneShotOfferwallProductIdOfferwall6f27b1aeGet**](#oneshotofferwallproductidofferwall6f27b1aeget) | **GET** /{product_id}/offerwall/6f27b1ae/ | One Shot Offerwall|
-|[**singleOfferwallProductIdOfferwall5fl8bpv5Get**](#singleofferwallproductidofferwall5fl8bpv5get) | **GET** /{product_id}/offerwall/5fl8bpv5/ | Single Offerwall|
-|[**starwallOfferwallProductIdOfferwallB59a2d2bGet**](#starwallofferwallproductidofferwallb59a2d2bget) | **GET** /{product_id}/offerwall/b59a2d2b/ | Starwall Offerwall|
|[**starwallPlusBlockOfferwallProductIdOfferwall7fa1b3f4Get**](#starwallplusblockofferwallproductidofferwall7fa1b3f4get) | **GET** /{product_id}/offerwall/7fa1b3f4/ | Starwall Plus Block Offerwall|
|[**starwallPlusBlockRecontactOfferwallProductIdOfferwall630db2a4Get**](#starwallplusblockrecontactofferwallproductidofferwall630db2a4get) | **GET** /{product_id}/offerwall/630db2a4/ | Starwall Plus Block Recontact Offerwall|
|[**starwallPlusOfferwallProductIdOfferwall5481f322Get**](#starwallplusofferwallproductidofferwall5481f322get) | **GET** /{product_id}/offerwall/5481f322/ | Starwall Plus Offerwall|
-|[**topNOfferwallProductIdOfferwall45b7228a7Get**](#topnofferwallproductidofferwall45b7228a7get) | **GET** /{product_id}/offerwall/45b7228a7/ | Topn Offerwall|
|[**topNPlusBlockOfferwallProductIdOfferwallD48cce47Get**](#topnplusblockofferwallproductidofferwalld48cce47get) | **GET** /{product_id}/offerwall/d48cce47/ | Topn Plus Block Offerwall|
|[**topNPlusBlockRecontactOfferwallProductIdOfferwall1e5f0af8Get**](#topnplusblockrecontactofferwallproductidofferwall1e5f0af8get) | **GET** /{product_id}/offerwall/1e5f0af8/ | Topn Plus Block Recontact Offerwall|
|[**topNPlusOfferwallProductIdOfferwallB145b803Get**](#topnplusofferwallproductidofferwallb145b803get) | **GET** /{product_id}/offerwall/b145b803/ | Topn Plus Offerwall|
@@ -476,164 +473,6 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-# **singleOfferwallProductIdOfferwall5fl8bpv5Get**
-> SingleEntryOfferWallResponse singleOfferwallProductIdOfferwall5fl8bpv5Get()
-
-Only returns a single bucket with the top scoring tasks.
-
-### Example
-
-```typescript
-import {
- OfferwallApi,
- Configuration
-} from './api';
-
-const configuration = new Configuration();
-const apiInstance = new OfferwallApi(configuration);
-
-let productId: string; //The Brokerage Product ID provided by GRL. (default to undefined)
-let bpuid: string; //A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. (default to undefined)
-let ip: string; //Respondent\'s IP address (IPv4 or IPv6). Either \'ip\' must be provided, or \'country_iso\' must be provided if \'ip\' is not provided. (optional) (default to undefined)
-let countryIso: string; //Respondent\'s country code (ISO 3166-1 alpha-2, lowercase) (optional) (default to undefined)
-let languages: Array<string>; //Respondent\'s desired languages (ISO 639-2/B, lowercase) (optional) (default to undefined)
-let behavior: string; //Allows using custom scoring functions. Please discuss directly with GRL. (optional) (default to undefined)
-let minPayout: string; //Decimal representation of the minimum amount of USD that any of the tasks will pay (optional) (default to undefined)
-let duration: number; //Maximum length of desired task (in seconds). (optional) (default to undefined)
-let minBinSize: number; //Minimum number of tasks that need to be in a bucket (optional) (default to 3)
-
-const { status, data } = await apiInstance.singleOfferwallProductIdOfferwall5fl8bpv5Get(
- productId,
- bpuid,
- ip,
- countryIso,
- languages,
- behavior,
- minPayout,
- duration,
- minBinSize
-);
-```
-
-### Parameters
-
-|Name | Type | Description | Notes|
-|------------- | ------------- | ------------- | -------------|
-| **productId** | [**string**] | The Brokerage Product ID provided by GRL. | defaults to undefined|
-| **bpuid** | [**string**] | A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. | defaults to undefined|
-| **ip** | [**string**] | Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided. | (optional) defaults to undefined|
-| **countryIso** | [**string**] | Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase) | (optional) defaults to undefined|
-| **languages** | **Array&lt;string&gt;** | Respondent\&#39;s desired languages (ISO 639-2/B, lowercase) | (optional) defaults to undefined|
-| **behavior** | [**string**] | Allows using custom scoring functions. Please discuss directly with GRL. | (optional) defaults to undefined|
-| **minPayout** | [**string**] | Decimal representation of the minimum amount of USD that any of the tasks will pay | (optional) defaults to undefined|
-| **duration** | [**number**] | Maximum length of desired task (in seconds). | (optional) defaults to undefined|
-| **minBinSize** | [**number**] | Minimum number of tasks that need to be in a bucket | (optional) defaults to 3|
-
-
-### Return type
-
-**SingleEntryOfferWallResponse**
-
-### Authorization
-
-No authorization required
-
-### HTTP request headers
-
- - **Content-Type**: Not defined
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-|**200** | Successful Response | - |
-|**422** | Validation Error | - |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
-# **starwallOfferwallProductIdOfferwallB59a2d2bGet**
-> StarwallOfferWallResponse starwallOfferwallProductIdOfferwallB59a2d2bGet()
-
-Returns an offerwall with buckets that are clustered by setting as seeds the highest scoring surveys for each bin, then the rest are distributed according to their Euclidean distance using the bucket\'s features.
-
-### Example
-
-```typescript
-import {
- OfferwallApi,
- Configuration
-} from './api';
-
-const configuration = new Configuration();
-const apiInstance = new OfferwallApi(configuration);
-
-let productId: string; //The Brokerage Product ID provided by GRL. (default to undefined)
-let bpuid: string; //A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. (default to undefined)
-let ip: string; //Respondent\'s IP address (IPv4 or IPv6). Either \'ip\' must be provided, or \'country_iso\' must be provided if \'ip\' is not provided. (optional) (default to undefined)
-let countryIso: string; //Respondent\'s country code (ISO 3166-1 alpha-2, lowercase) (optional) (default to undefined)
-let languages: Array<string>; //Respondent\'s desired languages (ISO 639-2/B, lowercase) (optional) (default to undefined)
-let behavior: string; //Allows using custom scoring functions. Please discuss directly with GRL. (optional) (default to undefined)
-let minPayout: string; //Decimal representation of the minimum amount of USD that any of the tasks will pay (optional) (default to undefined)
-let duration: number; //Maximum length of desired task (in seconds). (optional) (default to undefined)
-let nBins: number; //Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins=0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split. (optional) (default to 1)
-let minBinSize: number; //Minimum number of tasks that need to be in a bucket (optional) (default to 3)
-let splitBy: 'payout' | 'duration'; //Cluster tasks by payout or duration (optional) (default to 'payout')
-
-const { status, data } = await apiInstance.starwallOfferwallProductIdOfferwallB59a2d2bGet(
- productId,
- bpuid,
- ip,
- countryIso,
- languages,
- behavior,
- minPayout,
- duration,
- nBins,
- minBinSize,
- splitBy
-);
-```
-
-### Parameters
-
-|Name | Type | Description | Notes|
-|------------- | ------------- | ------------- | -------------|
-| **productId** | [**string**] | The Brokerage Product ID provided by GRL. | defaults to undefined|
-| **bpuid** | [**string**] | A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. | defaults to undefined|
-| **ip** | [**string**] | Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided. | (optional) defaults to undefined|
-| **countryIso** | [**string**] | Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase) | (optional) defaults to undefined|
-| **languages** | **Array&lt;string&gt;** | Respondent\&#39;s desired languages (ISO 639-2/B, lowercase) | (optional) defaults to undefined|
-| **behavior** | [**string**] | Allows using custom scoring functions. Please discuss directly with GRL. | (optional) defaults to undefined|
-| **minPayout** | [**string**] | Decimal representation of the minimum amount of USD that any of the tasks will pay | (optional) defaults to undefined|
-| **duration** | [**number**] | Maximum length of desired task (in seconds). | (optional) defaults to undefined|
-| **nBins** | [**number**] | Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split. | (optional) defaults to 1|
-| **minBinSize** | [**number**] | Minimum number of tasks that need to be in a bucket | (optional) defaults to 3|
-| **splitBy** | [**&#39;payout&#39; | &#39;duration&#39;**]**Array<&#39;payout&#39; &#124; &#39;duration&#39;>** | Cluster tasks by payout or duration | (optional) defaults to 'payout'|
-
-
-### Return type
-
-**StarwallOfferWallResponse**
-
-### Authorization
-
-No authorization required
-
-### HTTP request headers
-
- - **Content-Type**: Not defined
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-|**200** | Successful Response | - |
-|**422** | Validation Error | - |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
# **starwallPlusBlockOfferwallProductIdOfferwall7fa1b3f4Get**
> StarwallPlusBlockOfferWallResponse starwallPlusBlockOfferwallProductIdOfferwall7fa1b3f4Get()
@@ -880,88 +719,6 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-# **topNOfferwallProductIdOfferwall45b7228a7Get**
-> TopNOfferWallResponse topNOfferwallProductIdOfferwall45b7228a7Get()
-
-Returns an offerwall with buckets that are clustered by the `split_by` argument using KMeans clustering.
-
-### Example
-
-```typescript
-import {
- OfferwallApi,
- Configuration
-} from './api';
-
-const configuration = new Configuration();
-const apiInstance = new OfferwallApi(configuration);
-
-let productId: string; //The Brokerage Product ID provided by GRL. (default to undefined)
-let bpuid: string; //A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. (default to undefined)
-let ip: string; //Respondent\'s IP address (IPv4 or IPv6). Either \'ip\' must be provided, or \'country_iso\' must be provided if \'ip\' is not provided. (optional) (default to undefined)
-let countryIso: string; //Respondent\'s country code (ISO 3166-1 alpha-2, lowercase) (optional) (default to undefined)
-let languages: Array<string>; //Respondent\'s desired languages (ISO 639-2/B, lowercase) (optional) (default to undefined)
-let behavior: string; //Allows using custom scoring functions. Please discuss directly with GRL. (optional) (default to undefined)
-let minPayout: string; //Decimal representation of the minimum amount of USD that any of the tasks will pay (optional) (default to undefined)
-let duration: number; //Maximum length of desired task (in seconds). (optional) (default to undefined)
-let nBins: number; //Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins=0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split. (optional) (default to 1)
-let minBinSize: number; //Minimum number of tasks that need to be in a bucket (optional) (default to 3)
-let splitBy: 'payout' | 'duration'; //Cluster tasks by payout or duration (optional) (default to 'payout')
-
-const { status, data } = await apiInstance.topNOfferwallProductIdOfferwall45b7228a7Get(
- productId,
- bpuid,
- ip,
- countryIso,
- languages,
- behavior,
- minPayout,
- duration,
- nBins,
- minBinSize,
- splitBy
-);
-```
-
-### Parameters
-
-|Name | Type | Description | Notes|
-|------------- | ------------- | ------------- | -------------|
-| **productId** | [**string**] | The Brokerage Product ID provided by GRL. | defaults to undefined|
-| **bpuid** | [**string**] | A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. | defaults to undefined|
-| **ip** | [**string**] | Respondent\&#39;s IP address (IPv4 or IPv6). Either \&#39;ip\&#39; must be provided, or \&#39;country_iso\&#39; must be provided if \&#39;ip\&#39; is not provided. | (optional) defaults to undefined|
-| **countryIso** | [**string**] | Respondent\&#39;s country code (ISO 3166-1 alpha-2, lowercase) | (optional) defaults to undefined|
-| **languages** | **Array&lt;string&gt;** | Respondent\&#39;s desired languages (ISO 639-2/B, lowercase) | (optional) defaults to undefined|
-| **behavior** | [**string**] | Allows using custom scoring functions. Please discuss directly with GRL. | (optional) defaults to undefined|
-| **minPayout** | [**string**] | Decimal representation of the minimum amount of USD that any of the tasks will pay | (optional) defaults to undefined|
-| **duration** | [**number**] | Maximum length of desired task (in seconds). | (optional) defaults to undefined|
-| **nBins** | [**number**] | Number of bins requested in the offerwall. If n_bins&#x3D;1 there is no grouping and you get all duration + payout metrics on across all (as shown by the availability_count). n_bins&#x3D;0 will return back an empty bucket array, however, the availability_count will still show the total opportunities available for that bpuid + passed in parameter settings. n_bins&#x3D;∞ (or any positive integer) will return back the total number of bins capable of being uniquely split. | (optional) defaults to 1|
-| **minBinSize** | [**number**] | Minimum number of tasks that need to be in a bucket | (optional) defaults to 3|
-| **splitBy** | [**&#39;payout&#39; | &#39;duration&#39;**]**Array<&#39;payout&#39; &#124; &#39;duration&#39;>** | Cluster tasks by payout or duration | (optional) defaults to 'payout'|
-
-
-### Return type
-
-**TopNOfferWallResponse**
-
-### Authorization
-
-No authorization required
-
-### HTTP request headers
-
- - **Content-Type**: Not defined
- - **Accept**: application/json
-
-
-### HTTP response details
-| Status code | Description | Response headers |
-|-------------|-------------|------------------|
-|**200** | Successful Response | - |
-|**422** | Validation Error | - |
-
-[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
-
# **topNPlusBlockOfferwallProductIdOfferwallD48cce47Get**
> TopNPlusBlockOfferWallResponse topNPlusBlockOfferwallProductIdOfferwallD48cce47Get()
diff --git a/jb-ui/src/api_fsb/docs/OrderData1.md b/jb-ui/src/api_fsb/docs/OrderData1.md
new file mode 100644
index 0000000..0cd86fa
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/OrderData1.md
@@ -0,0 +1,37 @@
+# OrderData1
+
+Stores payout-type-specific order information that is returned from the external payout provider.
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**type** | **string** | | [optional] [default to TypeEnum_CashInMail]
+**shipping_cost** | **number** | | [default to undefined]
+**tracking_number** | **string** | | [optional] [default to undefined]
+**shipping_method** | [**ShippingMethod**](ShippingMethod.md) | | [optional] [default to undefined]
+**carrier** | [**ShippingCarrier**](ShippingCarrier.md) | | [optional] [default to undefined]
+**ship_date** | **string** | | [optional] [default to undefined]
+**estimated_delivery_date** | **string** | | [optional] [default to undefined]
+**delivery_status** | [**DeliveryStatus**](DeliveryStatus.md) | | [optional] [default to undefined]
+**last_updated** | **string** | | [optional] [default to undefined]
+
+## Example
+
+```typescript
+import { OrderData1 } from './api';
+
+const instance: OrderData1 = {
+ type,
+ shipping_cost,
+ tracking_number,
+ shipping_method,
+ carrier,
+ ship_date,
+ estimated_delivery_date,
+ delivery_status,
+ last_updated,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/PayoutTransformation.md b/jb-ui/src/api_fsb/docs/PayoutTransformation.md
index 378fde0..fdc0d1b 100644
--- a/jb-ui/src/api_fsb/docs/PayoutTransformation.md
+++ b/jb-ui/src/api_fsb/docs/PayoutTransformation.md
@@ -1,6 +1,6 @@
# PayoutTransformation
-This model describe how the bp_payout is converted to the user_payout. If None, the user_payout is None. If the user_wallet_enabled is `False`, the user_payout is used to 1) know how to transform the expected payouts for offerwall buckets (if min_payout is requested, this is based on the user_payout) 2) show the user (using the payout_format) how much they made (in the Task Status Response). If the user_wallet_enabled is `True`, then in addition to the above, the user_payout is the amount actually paid to the user\'s wallet.
+This model describe how the bp_payout is converted to the user_payout. If None, the user_payout is None. If the user_wallet_enabled is `False`, the user_payout is used to 1) know how to transform the expected payouts for offerwall buckets (if min_payout is requested, this is based on the user_payout) 2) show the user (using the payout_format) how much they made (in the Task Status Response). If the user_wallet_enabled is `True`, then in addition to the above, the user_payout is the amount actually paid to the user\'s wallet.
## Properties
diff --git a/jb-ui/src/api_fsb/docs/Product.md b/jb-ui/src/api_fsb/docs/Product.md
index 3dfe1d3..c62184a 100644
--- a/jb-ui/src/api_fsb/docs/Product.md
+++ b/jb-ui/src/api_fsb/docs/Product.md
@@ -8,7 +8,7 @@ Name | Type | Description | Notes
**id** | **string** | Unique identifier of the Brokerage Product | [optional] [default to undefined]
**name** | **string** | Name of the Brokerage Product. Must be unique within a Team | [default to undefined]
**enabled** | **boolean** | This is only used to hard block a Product in order to immediately &amp; safely protect against fraud entrances. | [optional] [default to true]
-**payments_enabled** | **boolean** | This is only to determine if ACH or Wire payments should be made to the Produce. | [optional] [default to true]
+**payments_enabled** | **boolean** | This is only to determine if ACH or Wire payments should be made to the Product. | [optional] [default to true]
**created** | **string** | | [optional] [default to undefined]
**team_id** | **string** | | [optional] [default to undefined]
**business_id** | **string** | | [optional] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/ProductBalances.md b/jb-ui/src/api_fsb/docs/ProductBalances.md
index 92a9170..30172f2 100644
--- a/jb-ui/src/api_fsb/docs/ProductBalances.md
+++ b/jb-ui/src/api_fsb/docs/ProductBalances.md
@@ -27,7 +27,7 @@ Name | Type | Description | Notes
**retainer_usd_str** | **string** | | [readonly] [default to undefined]
**available_balance** | **number** | The Available Balance is the amount that is currently, andimmediately available for withdraw from the Supplier\&#39;sbalance. Supplier Payments are made every Friday for Businesses with an ACH connected Bank Account to GRL, while a Business that requires an International Wire are issued on the last Friday of every Month. | [readonly] [default to undefined]
**available_balance_usd_str** | **string** | | [readonly] [default to undefined]
-**recoup** | **number** | | [readonly] [default to undefined]
+**recoup** | **number** | The amount that must be held back to recover a negative Product balance. This is $0.00 when the Product balance is positive or zero; otherwise it is the absolute value of the negative balance. Business-level payout calculations use this amount to offset deficits from one Product against available funds from other Products before issuing Supplier Payments. | [readonly] [default to undefined]
**recoup_usd_str** | **string** | | [readonly] [default to undefined]
**adjustment_percent** | **number** | The percentage of USDCent value that has been adjustedover all time for this Product. | [readonly] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/ProfilingConfig.md b/jb-ui/src/api_fsb/docs/ProfilingConfig.md
index 22d329d..22c2038 100644
--- a/jb-ui/src/api_fsb/docs/ProfilingConfig.md
+++ b/jb-ui/src/api_fsb/docs/ProfilingConfig.md
@@ -6,12 +6,12 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**enabled** | **boolean** | If False, the harmonizer/profiling system is not used at all. This should never be False unless special circumstances | [optional] [default to true]
-**grs_enabled** | **boolean** | If grs_enabled is False, and is_grs is passed in the profiling-questions call, then don\&#39;t actually return any questions. This allows a client to hit the endpoint with no limit and still get questions. In effect, this means that we\&#39;ll redirect the user through the GRS system but won\&#39;t present them any questions. | [optional] [default to true]
+**grs_enabled** | **boolean** | If grs_enabled is False, and is_grs is passed in the profiling-questions call, then don\&#39;t actually return any questions. This allows a client to hit the endpoint with no limit and still get questions. In effect, this means that we\&#39;ll redirect the user through the GRS system but won\&#39;t present them any questions. | [optional] [default to true]
**n_questions** | **number** | | [optional] [default to undefined]
**max_questions** | **number** | The max number of questions we would ask in a session | [optional] [default to 10]
**avg_question_count** | **number** | The average number of questions to ask in a session | [optional] [default to 5]
-**task_injection_freq_mult** | **number** | Scale how frequently we inject profiling questions, relative to the default.1 is default, 2 is twice as often. 10 means always. 0.5 half as often | [optional] [default to 1]
-**non_us_mult** | **number** | Non-us multiplier, used to increase freq and length of profilers in all non-us countries.This value is multiplied by task_injection_freq_mult and avg_question_count. | [optional] [default to 2]
+**task_injection_freq_mult** | **number** | Scale how frequently we inject profiling questions, relative to the default. 1 is default, 2 is twice as often. 10 means always. 0.5 half as often | [optional] [default to 1]
+**non_us_mult** | **number** | Non-us multiplier, used to increase freq and length of profilers in all non-us countries. This value is multiplied by task_injection_freq_mult and avg_question_count. | [optional] [default to 2]
**hidden_questions_expiration_hours** | **number** | How frequently we should refresh hidden questions | [optional] [default to 168]
## Example
diff --git a/jb-ui/src/api_fsb/docs/SupplyPolicy.md b/jb-ui/src/api_fsb/docs/SupplyPolicy.md
index 6d72fa9..8eb86eb 100644
--- a/jb-ui/src/api_fsb/docs/SupplyPolicy.md
+++ b/jb-ui/src/api_fsb/docs/SupplyPolicy.md
@@ -1,6 +1,6 @@
# SupplyPolicy
-One policy describing how GRL can interact with a marketplaces in a certain way. This is only used on the special \"global product\", and then internally in grpc logic.
+One policy describing how GRL can interact with a marketplaces in a certain way. This is only used on the special \"global product\", and then internally in grpc logic.
## Properties
diff --git a/jb-ui/src/api_fsb/docs/THLApi.md b/jb-ui/src/api_fsb/docs/THLApi.md
new file mode 100644
index 0000000..ed20c0a
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/THLApi.md
@@ -0,0 +1,60 @@
+# THLApi
+
+All URIs are relative to *https://fsb.generalresearch.com*
+
+|Method | HTTP request | Description|
+|------------- | ------------- | -------------|
+|[**manageCashoutThlManageCashoutPost**](#managecashoutthlmanagecashoutpost) | **POST** /thl/manage_cashout/ | Manage Cashout|
+
+# **manageCashoutThlManageCashoutPost**
+> UserPayoutEvent manageCashoutThlManageCashoutPost(manageCashoutBody)
+
+
+### Example
+
+```typescript
+import {
+ THLApi,
+ Configuration,
+ ManageCashoutBody
+} from './api';
+
+const configuration = new Configuration();
+const apiInstance = new THLApi(configuration);
+
+let manageCashoutBody: ManageCashoutBody; //
+
+const { status, data } = await apiInstance.manageCashoutThlManageCashoutPost(
+ manageCashoutBody
+);
+```
+
+### Parameters
+
+|Name | Type | Description | Notes|
+|------------- | ------------- | ------------- | -------------|
+| **manageCashoutBody** | **ManageCashoutBody**| | |
+
+
+### Return type
+
+**UserPayoutEvent**
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: application/json
+ - **Accept**: application/json
+
+
+### HTTP response details
+| Status code | Description | Response headers |
+|-------------|-------------|------------------|
+|**200** | Successful Response | - |
+|**422** | Validation Error | - |
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+
diff --git a/jb-ui/src/api_fsb/docs/UpkQuestion.md b/jb-ui/src/api_fsb/docs/UpkQuestion.md
index 332d09f..945e91b 100644
--- a/jb-ui/src/api_fsb/docs/UpkQuestion.md
+++ b/jb-ui/src/api_fsb/docs/UpkQuestion.md
@@ -12,7 +12,7 @@ Name | Type | Description | Notes
**language_iso** | **string** | | [default to undefined]
**question_text** | **string** | The text shown to respondents | [default to undefined]
**choices** | [**Array&lt;UpkQuestionChoice&gt;**](UpkQuestionChoice.md) | | [optional] [default to undefined]
-**selector** | [**Selector**](Selector.md) | | [optional] [default to undefined]
+**selector** | [**Selector**](Selector.md) | | [default to undefined]
**configuration** | [**UpkQuestionConfiguration**](UpkQuestionConfiguration.md) | | [optional] [default to undefined]
**validation** | [**UpkQuestionValidation**](UpkQuestionValidation.md) | | [optional] [default to undefined]
**importance** | [**UPKImportance**](UPKImportance.md) | | [optional] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/UpkQuestionOut.md b/jb-ui/src/api_fsb/docs/UpkQuestionOut.md
index 351ffaf..8d2f7ac 100644
--- a/jb-ui/src/api_fsb/docs/UpkQuestionOut.md
+++ b/jb-ui/src/api_fsb/docs/UpkQuestionOut.md
@@ -12,7 +12,7 @@ Name | Type | Description | Notes
**language_iso** | **string** | | [default to undefined]
**question_text** | **string** | The text shown to respondents | [default to undefined]
**choices** | [**Array&lt;UpkQuestionChoiceOut&gt;**](UpkQuestionChoiceOut.md) | | [optional] [default to undefined]
-**selector** | [**Selector**](Selector.md) | | [optional] [default to undefined]
+**selector** | [**Selector**](Selector.md) | | [default to undefined]
**configuration** | [**UpkQuestionConfiguration**](UpkQuestionConfiguration.md) | | [optional] [default to undefined]
**validation** | [**UpkQuestionValidation**](UpkQuestionValidation.md) | | [optional] [default to undefined]
**importance** | [**UPKImportance**](UPKImportance.md) | | [optional] [default to undefined]
diff --git a/jb-ui/src/api_fsb/docs/UserCpi.md b/jb-ui/src/api_fsb/docs/UserCpi.md
new file mode 100644
index 0000000..18048f3
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/UserCpi.md
@@ -0,0 +1,19 @@
+# UserCpi
+
+ The amount the user would earn from completing this task, if the status was a complete. If the BP has no payout xform, the user_cpi is None. This is analogous to the session\'s user_payout.
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+
+## Example
+
+```typescript
+import { UserCpi } from './api';
+
+const instance: UserCpi = {
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/UserDisplayedWalletBalance.md b/jb-ui/src/api_fsb/docs/UserDisplayedWalletBalance.md
new file mode 100644
index 0000000..78c82e6
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/UserDisplayedWalletBalance.md
@@ -0,0 +1,25 @@
+# UserDisplayedWalletBalance
+
+Combined user-visible balance for one ledger currency.
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**currency** | **string** | | [default to undefined]
+**amount** | **number** | Displayed balance in the currency\&#39;s smallest ledger unit. | [default to undefined]
+**amount_string** | **string** | | [optional] [default to undefined]
+
+## Example
+
+```typescript
+import { UserDisplayedWalletBalance } from './api';
+
+const instance: UserDisplayedWalletBalance = {
+ currency,
+ amount,
+ amount_string,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/UserLedgerTransactionTaskComplete.md b/jb-ui/src/api_fsb/docs/UserLedgerTransactionTaskComplete.md
index f513148..05cda73 100644
--- a/jb-ui/src/api_fsb/docs/UserLedgerTransactionTaskComplete.md
+++ b/jb-ui/src/api_fsb/docs/UserLedgerTransactionTaskComplete.md
@@ -1,6 +1,6 @@
# UserLedgerTransactionTaskComplete
-In a BP with user wallet enabled, the task-complete transaction would have line items for both the credit to the bp_wallet_account and credit to user_account. This is the user-detail, so we\'ve only caring about the user\'s payment.
+In a BP with user wallet enabled, the task-complete transaction would have line items for both the credit to the bp_wallet_account and credit to user_account. This is the user-detail, so we\'ve only caring about the user\'s payment.
## Properties
diff --git a/jb-ui/src/api_fsb/docs/UserLedgerWallet.md b/jb-ui/src/api_fsb/docs/UserLedgerWallet.md
new file mode 100644
index 0000000..d223586
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/UserLedgerWallet.md
@@ -0,0 +1,37 @@
+# UserLedgerWallet
+
+A user-owned ledger account exposed by the wallets endpoint.
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**amount** | **number** | (USD cents) The amount in the user\&#39;s wallet. | [default to undefined]
+**redeemable_amount** | **number** | (USD cents) The amount in the user\&#39;s wallet this is currently redeemable. | [default to undefined]
+**payout_format** | **string** | | [optional] [default to undefined]
+**amount_string** | **string** | | [optional] [default to undefined]
+**redeemable_amount_string** | **string** | | [optional] [default to undefined]
+**account_uuid** | **string** | A unique identifier for this Ledger Account | [default to undefined]
+**account_type** | **string** | | [default to undefined]
+**currency** | **string** | | [optional] [default to 'USD']
+**display_name** | **string** | Human-readable description of the Ledger Account | [default to undefined]
+
+## Example
+
+```typescript
+import { UserLedgerWallet } from './api';
+
+const instance: UserLedgerWallet = {
+ amount,
+ redeemable_amount,
+ payout_format,
+ amount_string,
+ redeemable_amount_string,
+ account_uuid,
+ account_type,
+ currency,
+ display_name,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/UserLedgerWallets.md b/jb-ui/src/api_fsb/docs/UserLedgerWallets.md
new file mode 100644
index 0000000..5d202a3
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/UserLedgerWallets.md
@@ -0,0 +1,22 @@
+# UserLedgerWallets
+
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**wallets** | [**Array&lt;UserLedgerWallet&gt;**](UserLedgerWallet.md) | | [optional] [default to undefined]
+**displayed_balances** | [**Array&lt;UserDisplayedWalletBalance&gt;**](UserDisplayedWalletBalance.md) | | [optional] [default to undefined]
+
+## Example
+
+```typescript
+import { UserLedgerWallets } from './api';
+
+const instance: UserLedgerWallets = {
+ wallets,
+ displayed_balances,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/UserPayoutEvent.md b/jb-ui/src/api_fsb/docs/UserPayoutEvent.md
new file mode 100644
index 0000000..02b62ab
--- /dev/null
+++ b/jb-ui/src/api_fsb/docs/UserPayoutEvent.md
@@ -0,0 +1,45 @@
+# UserPayoutEvent
+
+A user has requested to be paid from their wallet balance.
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**uuid** | **string** | | [optional] [default to undefined]
+**debit_account_uuid** | **string** | | [default to undefined]
+**cashout_method_uuid** | **string** | | [default to undefined]
+**created** | **string** | | [optional] [default to undefined]
+**amount** | **number** | The USDCent amount int. This cannot be 0 or negative | [default to undefined]
+**status** | [**PayoutStatus**](PayoutStatus.md) | | [optional] [default to undefined]
+**ext_ref_id** | **string** | | [optional] [default to undefined]
+**payout_type** | [**PayoutType**](PayoutType.md) | - &#x60;PAYPAL&#x60; &#x3D; PAYPAL - &#x60;TANGO&#x60; &#x3D; TANGO - &#x60;DWOLLA&#x60; &#x3D; DWOLLA - &#x60;ACH&#x60; &#x3D; ACH - &#x60;WIRE&#x60; &#x3D; WIRE - &#x60;CASH_IN_MAIL&#x60; &#x3D; CASH_IN_MAIL - &#x60;PRIZE&#x60; &#x3D; PRIZE - &#x60;AMT&#x60; &#x3D; AMT - &#x60;AMT_BONUS&#x60; &#x3D; AMT_BONUS - &#x60;AMT_ASSIGNMENT&#x60; &#x3D; AMT_HIT | [default to undefined]
+**request_data** | **object** | | [optional] [default to undefined]
+**order_data** | [**OrderData1**](OrderData1.md) | | [optional] [default to undefined]
+**account_reference_type** | **string** | | [optional] [default to undefined]
+**account_reference_uuid** | **string** | | [optional] [default to undefined]
+**description** | **string** | | [optional] [default to undefined]
+
+## Example
+
+```typescript
+import { UserPayoutEvent } from './api';
+
+const instance: UserPayoutEvent = {
+ uuid,
+ debit_account_uuid,
+ cashout_method_uuid,
+ created,
+ amount,
+ status,
+ ext_ref_id,
+ payout_type,
+ request_data,
+ order_data,
+ account_reference_type,
+ account_reference_uuid,
+ description,
+};
+```
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/jb-ui/src/api_fsb/docs/UserProfile.md b/jb-ui/src/api_fsb/docs/UserProfile.md
index 7bacbdf..843cb50 100644
--- a/jb-ui/src/api_fsb/docs/UserProfile.md
+++ b/jb-ui/src/api_fsb/docs/UserProfile.md
@@ -6,6 +6,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**email_address** | **string** | | [optional] [default to undefined]
+**display_name** | **string** | | [optional] [default to undefined]
**user** | [**User**](User.md) | | [default to undefined]
**marketplace_pids** | **{ [key: string]: string; }** | User\&#39;s PID in marketplaces | [optional] [default to undefined]
**streaks** | [**Array&lt;UserStreak&gt;**](UserStreak.md) | | [optional] [default to undefined]
@@ -20,6 +21,7 @@ import { UserProfile } from './api';
const instance: UserProfile = {
email_address,
+ display_name,
user,
marketplace_pids,
streaks,
diff --git a/jb-ui/src/api_fsb/docs/UserWalletConfig.md b/jb-ui/src/api_fsb/docs/UserWalletConfig.md
index 96d9587..2d9ef41 100644
--- a/jb-ui/src/api_fsb/docs/UserWalletConfig.md
+++ b/jb-ui/src/api_fsb/docs/UserWalletConfig.md
@@ -7,9 +7,11 @@ Stores configuration for the user wallet handling
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**enabled** | **boolean** | If enabled, the users\&#39; wallets are managed. | [optional] [default to false]
+**balance_type** | **string** | The balance used as the user\&#39;s displayed balance. | [optional] [default to BalanceTypeEnum_WalletBalance]
**amt** | **boolean** | Uses Amazon Mechanical Turk | [optional] [default to false]
-**supported_payout_types** | [**Set&lt;PayoutType&gt;**](PayoutType.md) | | [optional] [default to undefined]
+**supported_payout_types** | [**Array&lt;PayoutType&gt;**](PayoutType.md) | | [optional] [default to undefined]
**min_cashout** | **string** | | [optional] [default to undefined]
+**failed_attempt_credit** | **string** | | [optional] [default to undefined]
## Example
@@ -18,9 +20,11 @@ import { UserWalletConfig } from './api';
const instance: UserWalletConfig = {
enabled,
+ balance_type,
amt,
supported_payout_types,
min_cashout,
+ failed_attempt_credit,
};
```
diff --git a/jb-ui/src/api_fsb/docs/ValidationError.md b/jb-ui/src/api_fsb/docs/ValidationError.md
index d2e7ec1..912f97f 100644
--- a/jb-ui/src/api_fsb/docs/ValidationError.md
+++ b/jb-ui/src/api_fsb/docs/ValidationError.md
@@ -8,6 +8,8 @@ Name | Type | Description | Notes
**loc** | [**Array&lt;ValidationErrorLocInner&gt;**](ValidationErrorLocInner.md) | | [default to undefined]
**msg** | **string** | | [default to undefined]
**type** | **string** | | [default to undefined]
+**input** | **any** | | [optional] [default to undefined]
+**ctx** | **object** | | [optional] [default to undefined]
## Example
@@ -18,6 +20,8 @@ const instance: ValidationError = {
loc,
msg,
type,
+ input,
+ ctx,
};
```
diff --git a/jb-ui/src/api_fsb/docs/WallOut.md b/jb-ui/src/api_fsb/docs/WallOut.md
index aca3aef..89830a1 100644
--- a/jb-ui/src/api_fsb/docs/WallOut.md
+++ b/jb-ui/src/api_fsb/docs/WallOut.md
@@ -22,7 +22,7 @@ Name | Type | Description | Notes
**report_notes** | [**ReportNotes**](ReportNotes.md) | | [optional] [default to undefined]
**adjusted_status** | [**WallOutAdjustedStatus**](WallOutAdjustedStatus.md) | | [optional] [default to undefined]
**adjusted_timestamp** | [**AdjustedTimestamp**](AdjustedTimestamp.md) | | [optional] [default to undefined]
-**user_cpi** | **number** | The amount the user would earn from completing this task, if the status was a complete. If the BP has no payout xform, the user_cpi is None. This is analogous to the session\&#39;s user_payout. | [optional] [default to undefined]
+**user_cpi** | [**UserCpi**](UserCpi.md) | | [optional] [default to undefined]
**user_cpi_string** | [**UserCpiString**](UserCpiString.md) | | [optional] [default to undefined]
## Example
diff --git a/jb-ui/src/api_fsb/docs/WalletApi.md b/jb-ui/src/api_fsb/docs/WalletApi.md
index 80bd3ed..a4acfd4 100644
--- a/jb-ui/src/api_fsb/docs/WalletApi.md
+++ b/jb-ui/src/api_fsb/docs/WalletApi.md
@@ -4,15 +4,74 @@ All URIs are relative to *https://fsb.generalresearch.com*
|Method | HTTP request | Description|
|------------- | ------------- | -------------|
+|[**claimLatestAttemptCreditProductIdWalletAttemptCreditPost**](#claimlatestattemptcreditproductidwalletattemptcreditpost) | **POST** /{product_id}/wallet/attempt-credit/ | Claim Latest Attempt Credit|
|[**createCashoutMethodProductIdCashoutMethodsPost**](#createcashoutmethodproductidcashoutmethodspost) | **POST** /{product_id}/cashout_methods/ | Create Cashout Method|
|[**deleteCashoutMethodProductIdCashoutMethodsCashoutMethodIdDelete**](#deletecashoutmethodproductidcashoutmethodscashoutmethodiddelete) | **DELETE** /{product_id}/cashout_methods/{cashout_method_id}/ | Delete Cashout Method|
+|[**getAttemptCreditProductIdWalletAttemptCreditTsidGet**](#getattemptcreditproductidwalletattemptcredittsidget) | **GET** /{product_id}/wallet/attempt-credit/{tsid}/ | Get Attempt Credit|
|[**getCashoutDetailProductIdCashoutCashoutIdGet**](#getcashoutdetailproductidcashoutcashoutidget) | **GET** /{product_id}/cashout/{cashout_id}/ | Get Cashout Detail|
|[**getCashoutMethodsProductIdCashoutMethodsGet**](#getcashoutmethodsproductidcashoutmethodsget) | **GET** /{product_id}/cashout_methods/ | Get Cashout Methods|
|[**getExpectedRedemptionValueProductIdCashoutMethodCashoutMethodIdValueGet**](#getexpectedredemptionvalueproductidcashoutmethodcashoutmethodidvalueget) | **GET** /{product_id}/cashout_method/{cashout_method_id}/value/ | Get Expected Redemption Value|
|[**getUserTransactionHistoryProductIdTransactionHistoryGet**](#getusertransactionhistoryproductidtransactionhistoryget) | **GET** /{product_id}/transaction_history/ | Get User Transaction History|
|[**getUserWalletBalanceProductIdWalletGet**](#getuserwalletbalanceproductidwalletget) | **GET** /{product_id}/wallet/ | Get User Wallet Balance|
+|[**getUserWalletsProductIdWalletsGet**](#getuserwalletsproductidwalletsget) | **GET** /{product_id}/wallets/ | Get User Wallets|
|[**submitUserCashoutProductIdCashoutPost**](#submitusercashoutproductidcashoutpost) | **POST** /{product_id}/cashout/ | Submit User Cashout|
+# **claimLatestAttemptCreditProductIdWalletAttemptCreditPost**
+> AttemptCreditClaimResponse claimLatestAttemptCreditProductIdWalletAttemptCreditPost(attemptCreditClaimBody)
+
+Attempt to claim an Attempt Credit from the user\'s latest Session.
+
+### Example
+
+```typescript
+import {
+ WalletApi,
+ Configuration,
+ AttemptCreditClaimBody
+} from './api';
+
+const configuration = new Configuration();
+const apiInstance = new WalletApi(configuration);
+
+let productId: string; //The Brokerage Product ID provided by GRL. (default to undefined)
+let attemptCreditClaimBody: AttemptCreditClaimBody; //
+
+const { status, data } = await apiInstance.claimLatestAttemptCreditProductIdWalletAttemptCreditPost(
+ productId,
+ attemptCreditClaimBody
+);
+```
+
+### Parameters
+
+|Name | Type | Description | Notes|
+|------------- | ------------- | ------------- | -------------|
+| **attemptCreditClaimBody** | **AttemptCreditClaimBody**| | |
+| **productId** | [**string**] | The Brokerage Product ID provided by GRL. | defaults to undefined|
+
+
+### Return type
+
+**AttemptCreditClaimResponse**
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: application/json
+ - **Accept**: application/json
+
+
+### HTTP response details
+| Status code | Description | Response headers |
+|-------------|-------------|------------------|
+|**200** | Successful Response | - |
+|**422** | Validation Error | - |
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+
# **createCashoutMethodProductIdCashoutMethodsPost**
> CashoutMethodResponse createCashoutMethodProductIdCashoutMethodsPost(body)
@@ -127,6 +186,61 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+# **getAttemptCreditProductIdWalletAttemptCreditTsidGet**
+> AttemptCreditClaimResponse getAttemptCreditProductIdWalletAttemptCreditTsidGet()
+
+Get an Attempt Credit by a user\'s Session.
+
+### Example
+
+```typescript
+import {
+ WalletApi,
+ Configuration
+} from './api';
+
+const configuration = new Configuration();
+const apiInstance = new WalletApi(configuration);
+
+let productId: string; //The Brokerage Product ID provided by GRL. (default to undefined)
+let tsid: string; //A unique identifier for the session (default to undefined)
+
+const { status, data } = await apiInstance.getAttemptCreditProductIdWalletAttemptCreditTsidGet(
+ productId,
+ tsid
+);
+```
+
+### Parameters
+
+|Name | Type | Description | Notes|
+|------------- | ------------- | ------------- | -------------|
+| **productId** | [**string**] | The Brokerage Product ID provided by GRL. | defaults to undefined|
+| **tsid** | [**string**] | A unique identifier for the session | defaults to undefined|
+
+
+### Return type
+
+**AttemptCreditClaimResponse**
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/json
+
+
+### HTTP response details
+| Status code | Description | Response headers |
+|-------------|-------------|------------------|
+|**200** | Successful Response | - |
+|**422** | Validation Error | - |
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+
# **getCashoutDetailProductIdCashoutCashoutIdGet**
> CashoutRequestResponse getCashoutDetailProductIdCashoutCashoutIdGet()
@@ -420,6 +534,61 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+# **getUserWalletsProductIdWalletsGet**
+> UserLedgerWallets getUserWalletsProductIdWalletsGet()
+
+Retrieve a respondent\'s wallets and balances for display
+
+### Example
+
+```typescript
+import {
+ WalletApi,
+ Configuration
+} from './api';
+
+const configuration = new Configuration();
+const apiInstance = new WalletApi(configuration);
+
+let productId: string; //The Brokerage Product ID provided by GRL. (default to undefined)
+let bpuid: string; //A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. (default to undefined)
+
+const { status, data } = await apiInstance.getUserWalletsProductIdWalletsGet(
+ productId,
+ bpuid
+);
+```
+
+### Parameters
+
+|Name | Type | Description | Notes|
+|------------- | ------------- | ------------- | -------------|
+| **productId** | [**string**] | The Brokerage Product ID provided by GRL. | defaults to undefined|
+| **bpuid** | [**string**] | A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values. | defaults to undefined|
+
+
+### Return type
+
+**UserLedgerWallets**
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: Not defined
+ - **Accept**: application/json
+
+
+### HTTP response details
+| Status code | Description | Response headers |
+|-------------|-------------|------------------|
+|**200** | Successful Response | - |
+|**422** | Validation Error | - |
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
+
# **submitUserCashoutProductIdCashoutPost**
> CashoutRequestResponse submitUserCashoutProductIdCashoutPost(createCashoutRequest)
diff --git a/jb-ui/src/api_fsb/openapi.json b/jb-ui/src/api_fsb/openapi.json
index 8e9e5db..318e6cb 100644
--- a/jb-ui/src/api_fsb/openapi.json
+++ b/jb-ui/src/api_fsb/openapi.json
@@ -1 +1 @@
-{"openapi":"3.1.0","info":{"title":"General Research Full Service Brokerage API","version":"1.2.0"},"servers":[{"url":"https://fsb.generalresearch.com/","description":"Production environment"}],"paths":{"/{product_id}/offerwall/5fl8bpv5/":{"get":{"tags":["Offerwall"],"summary":"Single Offerwall","description":"Only returns a single bucket with the top scoring tasks.","operationId":"Single_Offerwall__product_id__offerwall_5fl8bpv5__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SingleEntryOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/45b7228a7/":{"get":{"tags":["Offerwall"],"summary":"Topn Offerwall","description":"Returns an offerwall with buckets that are clustered by the `split_by` argument\nusing KMeans clustering.","operationId":"TopN_Offerwall__product_id__offerwall_45b7228a7__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":1,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopNOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/b59a2d2b/":{"get":{"tags":["Offerwall"],"summary":"Starwall Offerwall","description":"Returns an offerwall with buckets that are clustered by setting as seeds the\nhighest scoring surveys for each bin, then the rest are distributed\naccording to their Euclidean distance using the bucket's features.","operationId":"Starwall_Offerwall__product_id__offerwall_b59a2d2b__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":1,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarwallOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/b145b803/":{"get":{"tags":["Offerwall"],"summary":"Topn Plus Offerwall","description":"Same as the TopNOfferWall, but the buckets include contents.","operationId":"TopN_Plus_Offerwall__product_id__offerwall_b145b803__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopNPlusOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/d48cce47/":{"get":{"tags":["Offerwall"],"summary":"Topn Plus Block Offerwall","description":"Same as the TopNOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.","operationId":"TopN_Plus_Block_Offerwall__product_id__offerwall_d48cce47__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopNPlusBlockOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/1e5f0af8/":{"get":{"tags":["Offerwall"],"summary":"Topn Plus Block Recontact Offerwall","description":"Same as the TopNOfferWall, but the buckets include contents, no buckets\nare returned if the user is blocked, and each bucket includes a\n`is_recontact` key.","operationId":"TopN_Plus_Block_Recontact_Offerwall__product_id__offerwall_1e5f0af8__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopNPlusBlockRecontactOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/5481f322/":{"get":{"tags":["Offerwall"],"summary":"Starwall Plus Offerwall","description":"Same as the StarwallOfferWall, but the buckets include contents.","operationId":"Starwall_Plus_Offerwall__product_id__offerwall_5481f322__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarwallPlusOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/7fa1b3f4/":{"get":{"tags":["Offerwall"],"summary":"Starwall Plus Block Offerwall","description":"Same as the StarwallOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.","operationId":"Starwall_Plus_Block_Offerwall__product_id__offerwall_7fa1b3f4__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarwallPlusBlockOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/630db2a4/":{"get":{"tags":["Offerwall"],"summary":"Starwall Plus Block Recontact Offerwall","description":"Same as the StarwallOfferWall, but the buckets include contents, no buckets\nare returned if the user is blocked, and each bucket includes a\n`is_recontact` key.","operationId":"Starwall_Plus_Block_Recontact_Offerwall__product_id__offerwall_630db2a4__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarwallPlusBlockRecontactOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/5fa23085/":{"get":{"tags":["Offerwall"],"summary":"Marketplace Offerwall","description":"Returns buckets grouped by marketplace, one per marketplace, with the\ntasks ordered by quality.","operationId":"Marketplace_Offerwall__product_id__offerwall_5fa23085__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/6f27b1ae/":{"get":{"tags":["Offerwall"],"summary":"One Shot Offerwall","description":"Each bucket has only 1 single task, and only basic info is returned\n about each bucket.","operationId":"One_Shot_Offerwall__product_id__offerwall_6f27b1ae__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":8,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"sources","in":"query","required":false,"schema":{"type":"array","uniqueItems":true,"items":{"$ref":"#/components/schemas/Source"},"description":"Restrict tasks to those from these marketplaces only.","title":"Sources"},"description":"Restrict tasks to those from these marketplaces only."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OneShotOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/55a4e1a9/":{"get":{"tags":["Offerwall"],"summary":"Wxet Offerwall","description":"Each bucket has only 1 single task, and only basic info is returned\n about each bucket.","operationId":"WXET_Offerwall__product_id__offerwall_55a4e1a9__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":8,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WXETOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/37d1da64/":{"get":{"tags":["Offerwall"],"summary":"Offerwall Softpair","description":"This offerwall contains tasks for which the user has a conditional\neligibility. The questions that a user must answer to determine the\neligibility are included within each bucket. Additionally, the question\ndefinitions are included for convenience.","operationId":"offerwall_softpair__product_id__offerwall_37d1da64__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":12,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":1,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"max_options","in":"query","required":false,"schema":{"type":"integer","description":"Max number of options an allowed question can have (allowed to be asked)","default":40,"title":"Max Options"},"description":"Max number of options an allowed question can have (allowed to be asked)"},{"name":"max_questions","in":"query","required":false,"schema":{"type":"integer","description":"Max number of missing questions on a single bin","default":3,"title":"Max Questions"},"description":"Max number of missing questions on a single bin"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/37d1da64/{offerwall_id}/":{"post":{"tags":["Offerwall"],"summary":"Offerwall Softpair Post","description":"This is a custom endpoint for a softpair-style offerwall that allows\nyou to update profiling answers and then immediately get back the\nupdated offerwall","operationId":"offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"offerwall_id","in":"path","required":true,"schema":{"type":"string","description":"The offerwall ID the user is interacting with","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"],"title":"Offerwall Id"},"description":"The offerwall ID the user is interacting with"},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A session id (uuid4.hex)","examples":["dd6aa32cfe834839a80195563f528337"],"title":"Session Id"},"description":"A session id (uuid4.hex)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/7a89dcdb/":{"get":{"tags":["Offerwall"],"summary":"Offerwall Softpair Block","description":"This offerwall contains tasks for which the user has a conditional\neligibility. The questions that a user must answer to determine the\neligibility are included within each bucket. Additionally, the question\ndefinitions are included for convenience.\nNo buckets are returned if the user is blocked.","operationId":"offerwall_softpair_block__product_id__offerwall_7a89dcdb__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":12,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":1,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"max_options","in":"query","required":false,"schema":{"type":"integer","description":"Max number of options an allowed question can have (allowed to be asked)","default":40,"title":"Max Options"},"description":"Max number of options an allowed question can have (allowed to be asked)"},{"name":"max_questions","in":"query","required":false,"schema":{"type":"integer","description":"Max number of missing questions on a single bin","default":3,"title":"Max Questions"},"description":"Max number of missing questions on a single bin"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/7a89dcdb/{offerwall_id}/":{"post":{"tags":["Offerwall"],"summary":"Offerwall Softpair Block Post","description":"This is a custom endpoint for a softpair-style offerwall that allows\nyou to update profiling answers and then immediately get back the\nupdated offerwall","operationId":"offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"offerwall_id","in":"path","required":true,"schema":{"type":"string","description":"The offerwall ID the user is interacting with","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"],"title":"Offerwall Id"},"description":"The offerwall ID the user is interacting with"},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A session id (uuid4.hex)","examples":["dd6aa32cfe834839a80195563f528337"],"title":"Session Id"},"description":"A session id (uuid4.hex)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/status/{tsid}/":{"get":{"tags":["Status"],"summary":"Get Task Status","description":"Retrieve the status of a session by a specific Task Status ID (`tsid`)\nthat is provided in the redirect.\n\nGiven a `tsid`, get back the status of the wall event. This endpoint\nconflates the idea of a wall event and a session, but for these\npurposes, the status and payout of the last wall event in a session\nequals the status and payout for the session.","operationId":"Get_Task_Status__product_id__status__tsid___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"tsid","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Task Status ID","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"description":"A unique identifier for the session"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskStatusResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusInfoResponseFail"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusInfoResponseFail"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusInfoResponseFail"}}},"description":"Internal Server Error"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/status/":{"get":{"tags":["Status"],"summary":"List Task Statuses","operationId":"List_Task_Statuses__product_id__status__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":false,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Filters the returned task status to only include those done by this user.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Filters the returned task status to only include those done by this user."},{"name":"started_after","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were started after this timestamp. If `NULL`, default is 10 days ago.","examples":["2026-02-17T00:46:04.812196Z",1771202765],"title":"Started After"},"description":"Retrieve sessions which were started after this timestamp. If `NULL`, default is 10 days ago."},{"name":"started_before","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were started before this timestamp. If `NULL`, default is now.","title":"Started Before"},"description":"Retrieve sessions which were started before this timestamp. If `NULL`, default is now."},{"name":"status","in":"query","required":false,"schema":{"type":"integer","description":"Filter for sessions with this status. See Task Status for description of status.","examples":[3],"title":"Status"},"description":"Filter for sessions with this status. See Task Status for description of status."},{"name":"reconciled","in":"query","required":false,"schema":{"type":"boolean","description":"Only retrieve sessions that have been adjusted. If `reconciled` is True, `adjusted_after` is required.","default":false,"title":"Reconciled"},"description":"Only retrieve sessions that have been adjusted. If `reconciled` is True, `adjusted_after` is required."},{"name":"adjusted_after","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were adjusted after this timestamp.","title":"Adjusted After"},"description":"Retrieve sessions which were adjusted after this timestamp."},{"name":"adjusted_before","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were adjusted before this timestamp. Default is now.","title":"Adjusted Before"},"description":"Retrieve sessions which were adjusted before this timestamp. Default is now."},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated fields to order by","examples":["-started","started"],"default":"-started","title":"Order By"},"description":"Comma-separated fields to order by"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TasksStatusResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponseFailure"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponseFailure"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponseFailure"}}},"description":"Internal Server Error"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/report/":{"post":{"tags":["Report"],"summary":"Report Task","description":"Send a \"Task Report\" for a respondent's latest started survey,\nregardless of the survey's outcome. Task Reports cannot be provided for\ntask attempts by tsid, or through any other method, they must be given\nimmediately after the respondent's task attempt.\n\nIf a latest attempt can't be found, a ReportTaskResponse is still returned.\n\nIf multiple reasons want to be provided, they should be done at the\nsame time. If multiple reports are given for the same latest started\ntask, the note attribute will be overwritten, while the new unique\nreasons will be appended to the task attempt.\n\nTask Report system contributions by client applications are immediately\nleveraged to aid yield management strategies. For those reasons, it's\nimportant that the respondent submits a Task Report as soon as possible\nand applications doesn't offload this request for a later time. Task\nReport timestamps are a critical component of understanding a Task\nexperience for a respondent.\n\nFor the BP to tell us about a bad survey they want to report\nThe POSTed data looks like:\n {\n 'bpuid': '1234',\n 'reasons': [2],\n 'notes': \"This survey was the worst!\"\n }\nReturns {'status': 'success', 'msg': error_msg}","operationId":"report_task__product_id__report__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportTask"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/profiling-questions/":{"get":{"tags":["Profiling Questions"],"summary":"Get Profiling Questions","description":"Gets a list of profiling questions to ask this user. These questions\nare, as of right now, unanswered. Once a question is answered, it\n(and any other question whose answer is inferred from other answers) is\nremoved from the list. The questions returned are ordered by\nimportance (the key task_score) in descending order.","operationId":"get_profiling_questions__product_id__profiling_questions__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"language_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{3}$","description":"Respondent's desired language (ISO 639-2/B, lowercase)","examples":["eng"],"title":"Language Iso"},"description":"Respondent's desired language (ISO 639-2/B, lowercase)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"description":"Number of questions to return. Questions are ordered, so, selects the N most important. If no limit is passed, then the number of questions returned is dynamically calculated by the questions' importance.","title":"Limit"},"description":"Number of questions to return. Questions are ordered, so, selects the N most important. If no limit is passed, then the number of questions returned is dynamically calculated by the questions' importance."},{"name":"is_grs","in":"query","required":false,"schema":{"type":"boolean","description":"If it's the GRS system.","default":false,"title":"Is Grs"},"description":"If it's the GRS system."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpkQuestionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Profiling Questions"],"summary":"Submit Profiling Questions","description":"Send the answers to one or more of these questions for a user. A\nquestion is uniquely specified by the question_id key. The answer is:\nthe choice_id if the question_type is \"MC\" the actual entered text if\nthe question_type is \"TE\"","operationId":"submit_profiling_questions__product_id__profiling_questions__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"session_id","in":"query","required":false,"schema":{"type":"string","description":"The unique identifier for a session in which these questions were asked. Must be a valid UUID. Optional.","title":"Session Id"},"description":"The unique identifier for a session in which these questions were asked. Must be a valid UUID. Optional."},{"name":"async","in":"query","required":false,"schema":{"type":"boolean","description":"For internal use.","default":true,"title":"Async"},"description":"For internal use."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_submit_profiling_questions__product_id__profiling_questions__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/profiling-info/":{"get":{"tags":["Profiling Questions"],"summary":"Profiling Info","description":"Get UPK Ontology (list of properties, property info, and allowed values)","operationId":"profiling_info__product_id__profiling_info__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"country_iso","in":"query","required":true,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"language_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{3}$","description":"Respondent's desired language (ISO 639-2/B, lowercase)","examples":["eng"],"title":"Language Iso"},"description":"Respondent's desired language (ISO 639-2/B, lowercase)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilingInfoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/user-profile/":{"get":{"tags":["Profiling Questions"],"summary":"User Profile","operationId":"user_profile__product_id__user_profile__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"country_iso","in":"query","required":true,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"language_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{3}$","description":"Respondent's desired language (ISO 639-2/B, lowercase)","examples":["eng"],"title":"Language Iso"},"description":"Respondent's desired language (ISO 639-2/B, lowercase)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/user/{product_user_id}/profile/":{"get":{"tags":["Product User"],"summary":"User Profile","operationId":"user_profile__product_id__user__product_user_id__profile__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Product User"],"summary":"User Profile Update","operationId":"user_profile_update__product_id__user__product_user_id__profile__patch","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/user/by-marketplace-pid/":{"get":{"tags":["Product User"],"summary":"User Profile Filter By Marketplace Pid","operationId":"user_profile_filter_by_marketplace_pid__product_id__user_by_marketplace_pid__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"source","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Source","description":"The marketplace to search"},"description":"The marketplace to search"},{"name":"pid","in":"query","required":true,"schema":{"type":"array","items":{"type":"string","minLength":32,"maxLength":32},"description":"The user's marketplace PID. Supports multiple params","title":"Pid"},"description":"The user's marketplace PID. Supports multiple params"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfilesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/leaderboard/timespan/{board_code}/":{"get":{"tags":["Leaderboard"],"summary":"Timespan Leaderboard","operationId":"Timespan_Leaderboard__product_id__leaderboard_timespan__board_code___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"board_code","in":"path","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},"description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},{"name":"freq","in":"query","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},"description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.","examples":["us"],"title":"Country Iso"},"description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request."},{"name":"bpuid","in":"query","required":false,"schema":{"type":"string","minLength":3,"maxLength":128,"description":"Brokerage Product User ID. If passed, this results in the filtering of rows to include this user's row, plus rows above and below in rank (up to `limit` rows). Otherwise, the top `limit` rows are returned.","examples":["app-user-9329ebd"],"title":"Bpuid"},"description":"Brokerage Product User ID. If passed, this results in the filtering of rows to include this user's row, plus rows above and below in rank (up to `limit` rows). Otherwise, the top `limit` rows are returned."},{"name":"within_time","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Any local timestamp falling within the desired leaderboard's period. If not passed, uses the country's current time period.","examples":["2024-02-27","2024-02-27T15:30:00"],"title":"Within Time"},"description":"Any local timestamp falling within the desired leaderboard's period. If not passed, uses the country's current time period."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMaximum":5000,"exclusiveMinimum":0,"description":"Max number of rows to return","default":50,"title":"Limit"},"description":"Max number of rows to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/leaderboard/timespan/{board_code}/winners/":{"get":{"tags":["Leaderboard"],"summary":"Leaderboard Winners","description":"Get the Winners of leaderboard contests","operationId":"Leaderboard_Winners__product_id__leaderboard_timespan__board_code__winners__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"board_code","in":"path","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},"description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},{"name":"freq","in":"query","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},"description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.","examples":["us"],"title":"Country Iso"},"description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardWinnerResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/{contest_uuid}/user/{product_user_id}/":{"get":{"tags":["Contest"],"summary":"Get Contest User View","description":"Gets a Contest. Includes several keys that are specific to the requesting user:\n e.g. user_winnings, user_amount.","operationId":"Get_Contest_User_View__product_id__contest__contest_uuid__user__product_user_id___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"contest_uuid","in":"path","required":true,"schema":{"type":"string","title":"Contest Uuid"}},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}],"title":"Response Get Contest User View Product Id Contest Contest Uuid User Product User Id Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/user/{product_user_id}/entered/":{"get":{"tags":["Contest"],"summary":"List Contests User Entered","description":"Get contests the requesting user has entered. This includes contests such as milestone\n contests where the user was automatically entered by having a complete for instance.","operationId":"List_Contests_User_Entered__product_id__contest_user__product_user_id__entered__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}]},"title":"Response List Contests User Entered Product Id Contest User Product User Id Entered Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/user/{product_user_id}/eligible/":{"get":{"tags":["Contest"],"summary":"List Contests User Eligible","description":"Get contests the requesting user is eligible for.\nContest eligibility may involve the user's country, which is determined by the ip address\n of THIS request.","operationId":"List_Contests_User_Eligible__product_id__contest_user__product_user_id__eligible__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}]},"title":"Response List Contests User Eligible Product Id Contest User Product User Id Eligible Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/user/{product_user_id}/winner/":{"get":{"tags":["Contest"],"summary":"List Contests User Winner","description":"Get contests the requesting user has won a prize for.","operationId":"List_Contests_User_Winner__product_id__contest_user__product_user_id__winner__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}]},"title":"Response List Contests User Winner Product Id Contest User Product User Id Winner Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/wallet/":{"get":{"tags":["Wallet"],"summary":"Get User Wallet Balance","description":"Retrieve the current balance of a respondent's wallet balance for display","operationId":"get_user_wallet_balance__product_id__wallet__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserWalletBalanceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout_methods/":{"get":{"tags":["Wallet"],"summary":"Get Cashout Methods","description":"Retrieve the current available mechanisms that a user can use to retrieve funds.","operationId":"get_cashout_methods__product_id__cashout_methods__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutMethodsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Wallet"],"summary":"Create Cashout Method","description":"A user can only have 1 unique Cashout Method of any type at a time (eg. they can't create multiple paypal\npayout methods). Cashout Methods cannot be edited, they can only be created or deleted. Creating different\nCashout Methods will require type-dependent request data attributes in order to be successfully created.\n\nCurrently only creating paypal or Cash in Mail cashout methods are supported","operationId":"create_cashout_method__product_id__cashout_methods__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CreatePayPalCashoutMethodRequest"},{"$ref":"#/components/schemas/CreateCashMailCashoutMethodRequest"}],"discriminator":{"propertyName":"type","mapping":{"PAYPAL":"#/components/schemas/CreatePayPalCashoutMethodRequest","CASH_IN_MAIL":"#/components/schemas/CreateCashMailCashoutMethodRequest"}},"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutMethodResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout_methods/{cashout_method_id}/":{"delete":{"tags":["Wallet"],"summary":"Delete Cashout Method","description":"Delete a cashout method","operationId":"delete_cashout_method__product_id__cashout_methods__cashout_method_id___delete","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"cashout_method_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"description":"The ID of the cashout method to delete","title":"Cashout Method Id"},"description":"The ID of the cashout method to delete"},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout/":{"post":{"tags":["Wallet"],"summary":"Submit User Cashout","description":"Request a cashout taken from a user's available wallet balance, to be paid via a particular\ncashout method.","operationId":"submit_user_cashout__product_id__cashout__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCashoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutRequestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout/{cashout_id}/":{"get":{"tags":["Wallet"],"summary":"Get Cashout Detail","description":"Retrieve the details for a specific Cashout event","operationId":"get_cashout_detail__product_id__cashout__cashout_id___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"cashout_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"description":"The cashout event ID","title":"Cashout Id"},"description":"The cashout event ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutRequestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/transaction_history/":{"get":{"tags":["Wallet"],"summary":"Get User Transaction History","description":"Return array of user events that altered their wallet balance","operationId":"get_user_transaction_history__product_id__transaction_history__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"created_after","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Filter transactions created after this timestamp","examples":["2025-01-01T04:20:00.000000Z"],"title":"Created After"},"description":"Filter transactions created after this timestamp"},{"name":"created_before","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Filter transactions created before this timestamp","examples":["2026-02-17T00:46:04.851591Z"],"title":"Created Before"},"description":"Filter transactions created before this timestamp"},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated fields to order by","examples":["-created","created"],"default":"created","title":"Order By"},"description":"Comma-separated fields to order by"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLedgerTransactionsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout_method/{cashout_method_id}/value/":{"get":{"tags":["Wallet"],"summary":"Get Expected Redemption Value","description":"Use this function to get the \"value\" (in local currency, e.g. CAD, BTC) for this\n cashout_method, for amount (in USD cents).","operationId":"get_expected_redemption_value__product_id__cashout_method__cashout_method_id__value__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"cashout_method_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"description":"The ID of the cashout method","examples":["0d363971792249b1a34586f092819e4b"],"title":"Cashout Method Id"},"description":"The ID of the cashout method"},{"name":"amount","in":"query","required":true,"schema":{"type":"integer","description":"(USD cents) The amount to convert","examples":[100],"title":"Amount"},"description":"(USD cents) The amount to convert"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutMethodForeignValueResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/inventory/":{"get":{"tags":["Dashboard"],"summary":"Marketplace Inventory","operationId":"marketplace_inventory_dashboard_inventory__get","parameters":[{"name":"marketplace","in":"query","required":true,"schema":{"const":"WXET","type":"string","examples":["WXET"],"title":"Marketplace"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ws/debug/":{"get":{"tags":["Streams"],"summary":"Websocket Debug Page","operationId":"websocket_debug_page_ws_debug__get","parameters":[{"name":"product_id","in":"query","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Product Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ws/events/docs/":{"get":{"tags":["Streams"],"summary":"Websocket Events Docs","description":"WebSocket endpoint: `/ws/events/`\n\nProtocol:\n- Client connects\n- Client sends a SubscribeMessage `{ kind: \"subscribe\", product_id: \"{product_id}\" }`\n- Server sends a PingMessage `{ kind: \"ping\" }`\n- Client must reply a PongMessage: `{ kind: \"pong\" }`\n- Other messages are EventMessage or StatsMessage\n\nClose on missing pong after 20s.","operationId":"websocket_events_docs_ws_events_docs__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/EventMessage"},{"$ref":"#/components/schemas/StatsMessage"},{"$ref":"#/components/schemas/PingMessage"},{"$ref":"#/components/schemas/SubscribeMessage"},{"$ref":"#/components/schemas/PongMessage"}],"title":"Response Websocket Events Docs Ws Events Docs Get"}}}}}}}},"components":{"schemas":{"AccountType":{"type":"string","enum":["bp_commission","bp_wallet","user_wallet","cash","revenue","expense","contest_wallet","credit_line","wa_wallet","wa_budget_pool","wa_held","wa_credit_line"],"title":"AccountType"},"AdjustmentType":{"properties":{"amount":{"type":"integer","title":"Amount","description":"The total amount (in USD cents) that the Brokerage Producthas earned within a respective time period from a specificSource of Tasks."},"adjustment":{"$ref":"#/components/schemas/SessionAdjustedStatus","description":" - `ac` = ADJUSTED_TO_COMPLETE\n - `af` = ADJUSTED_TO_FAIL\n - `pa` = PAYOUT_ADJUSTMENT","examples":["af"]}},"type":"object","required":["amount","adjustment"],"title":"AdjustmentType"},"AggregateBySource":{"properties":{"total":{"type":"integer","minimum":0.0,"title":"Total","default":0},"by_source":{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object","title":"By Source"}},"type":"object","title":"AggregateBySource"},"AmtCashoutMethodData":{"properties":{"type":{"type":"string","const":"AMT","title":"Type","default":"AMT"}},"type":"object","title":"AmtCashoutMethodData"},"AuditLog":{"properties":{"id":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Id"},"user_id":{"type":"integer","exclusiveMinimum":0.0,"title":"User Id"},"created":{"type":"string","format":"date-time","title":"Created","description":"When did this event occur","examples":["2026-02-17T00:46:02.709649Z"]},"level":{"$ref":"#/components/schemas/AuditLogLevel","description":"The level of importance for this event. Works the same as python logging levels. It is an integer 0 - 50, and implementers of this field could map it to the predefined levels: (`CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`).This is NOT the same concept as the 'strength' of whatever event happened; it is just for sorting, filtering and display purposes. For e.g. multiple level 20 events != the 'importance' of one level 40 event.","examples":[30]},"event_type":{"type":"string","maxLength":64,"title":"Event Type","examples":["entrance-limit"]},"event_msg":{"anyOf":[{"type":"string","maxLength":256,"minLength":3},{"type":"null"}],"title":"Event Msg","description":"The event message. Could be displayed on user's page"},"event_value":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Event Value","description":"Optionally store a numeric value associated with this event. For e.g. if we recalculate the user's normalized recon rate, and it is 'high', we could store an event like (event_type='recon-rate', event_msg='higher than allowed recon rate' event_value=0.42)","examples":[0.42]}},"type":"object","required":["user_id","level","event_type"],"title":"AuditLog","description":"Table / Model for logging \"actions\" taken by a user or \"events\" that\nare related to a User"},"AuditLogLevel":{"type":"integer","enum":[50,50,40,30,30,20,10,0],"title":"AuditLogLevel"},"Body_offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/UserQuestionAnswerIn"},"type":"array","title":"Answers"}},"type":"object","required":["answers"],"title":"Body_offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post"},"Body_offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/UserQuestionAnswerIn"},"type":"array","title":"Answers"}},"type":"object","required":["answers"],"title":"Body_offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post"},"Body_submit_profiling_questions__product_id__profiling_questions__post":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/UserQuestionAnswerIn"},"type":"array","title":"Answers"}},"type":"object","required":["answers"],"title":"Body_submit_profiling_questions__product_id__profiling_questions__post"},"BrokerageProductPayoutEvent":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Payout Event Unique Identifier","examples":["9453cd076713426cb68d05591c7145aa"]},"debit_account_uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Debit Account Uuid","description":"The LedgerAccount.uuid that money is being requested from. Thie User or Brokerage Product is retrievable through the LedgerAccount.reference_uuid","examples":["18298cb1583846fbb06e4747b5310693"]},"cashout_method_uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Cashout Method Uuid","description":"References a row in the account_cashoutmethod table. This is the cashout method that was used to request this payout. (A cashout is the same thing as a payout)","examples":["a6dc1fc1bf934557b952f253dee12813"]},"created":{"type":"string","format":"date-time","title":"Created"},"amount":{"type":"integer","exclusiveMaximum":9.223372036854776e+18,"exclusiveMinimum":0.0,"title":"Amount","description":"The USDCent amount int. This cannot be 0 or negative","examples":[531]},"status":{"anyOf":[{"$ref":"#/components/schemas/PayoutStatus"},{"type":"null"}],"description":" - `PENDING` = PENDING\n - `APPROVED` = APPROVED\n - `REJECTED` = REJECTED\n - `CANCELLED` = CANCELLED\n - `FAILED` = FAILED\n - `COMPLETE` = COMPLETE","default":"PENDING","examples":["COMPLETE"]},"ext_ref_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ext Ref Id"},"payout_type":{"$ref":"#/components/schemas/PayoutType","description":" - `PAYPAL` = PAYPAL\n - `TANGO` = TANGO\n - `DWOLLA` = DWOLLA\n - `ACH` = ACH\n - `WIRE` = WIRE\n - `CASH_IN_MAIL` = CASH_IN_MAIL\n - `PRIZE` = PRIZE\n - `AMT` = AMT\n - `AMT_BONUS` = AMT_BONUS\n - `AMT_ASSIGNMENT` = AMT_HIT","examples":["ACH"]},"request_data":{"additionalProperties":true,"type":"object","title":"Request Data","description":"Stores payout-type-specific information that is used to request this payout from the external provider."},"order_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"$ref":"#/components/schemas/CashMailOrderData"},{"type":"null"}],"title":"Order Data","description":"Stores payout-type-specific order information that is returned from the external payout provider."},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"The Brokerage Product that was paid out","examples":["1108d053e4fa47c5b0dbdcd03a7981e7"]},"method":{"$ref":"#/components/schemas/PayoutType","description":" - `PAYPAL` = PAYPAL\n - `TANGO` = TANGO\n - `DWOLLA` = DWOLLA\n - `ACH` = ACH\n - `WIRE` = WIRE\n - `CASH_IN_MAIL` = CASH_IN_MAIL\n - `PRIZE` = PRIZE\n - `AMT` = AMT\n - `AMT_BONUS` = AMT_BONUS\n - `AMT_ASSIGNMENT` = AMT_HIT","readOnly":true,"examples":["ACH"]},"amount_usd":{"type":"integer","minimum":0.0,"title":"Amount Usd","readOnly":true,"examples":["$10,000.000"]},"amount_usd_str":{"type":"string","title":"Amount Usd Str","readOnly":true,"examples":["$10,000.000"]}},"type":"object","required":["debit_account_uuid","cashout_method_uuid","amount","payout_type","product_id","method","amount_usd","amount_usd_str"],"title":"BrokerageProductPayoutEvent","description":"The amount\n\n- created: When the Brokerage Product was paid out"},"BucketTask":{"properties":{"id":{"type":"string","maxLength":32,"minLength":1,"title":"Id","description":"The internal task id for this task within the marketplace","examples":["6ov9jz3"]},"id_code":{"type":"string","maxLength":35,"minLength":3,"pattern":"^[a-z]{1,2}\\:.*","title":"Id Code","description":"The namespaced task id for this task within the marketplace","examples":["o:6ov9jz3"]},"source":{"$ref":"#/components/schemas/Source","examples":["o"]},"loi":{"type":"integer","maximum":5400.0,"exclusiveMinimum":1.0,"title":"Loi","description":"expected loi in seconds","examples":[612]},"payout":{"type":"integer","exclusiveMinimum":1.0,"title":"Payout","description":"integer cents","examples":[123]}},"type":"object","required":["id","id_code","source","loi","payout"],"title":"BucketTask","description":"This represents one of the \"tasks\" within a bucket's ordered list of tasks."},"Cardinality":{"type":"string","enum":["*","?"],"title":"Cardinality"},"CashMailCashoutMethodData":{"properties":{"type":{"type":"string","const":"CASH_IN_MAIL","title":"Type","default":"CASH_IN_MAIL"},"delivery_address":{"$ref":"#/components/schemas/USDeliveryAddress","description":"Delivery address where payment should be sent"}},"type":"object","required":["delivery_address"],"title":"CashMailCashoutMethodData"},"CashMailOrderData":{"properties":{"type":{"type":"string","const":"CASH_IN_MAIL","title":"Type","default":"CASH_IN_MAIL"},"shipping_cost":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Shipping Cost","description":"(USD cents) The shipping cost. This amount get charged to the BP."},"tracking_number":{"anyOf":[{"type":"string","maxLength":50,"minLength":1},{"type":"null"}],"title":"Tracking Number"},"shipping_method":{"anyOf":[{"$ref":"#/components/schemas/ShippingMethod","maxLength":50,"minLength":1},{"type":"null"}],"description":"Standard, express, etc."},"carrier":{"anyOf":[{"$ref":"#/components/schemas/ShippingCarrier","maxLength":50,"minLength":1},{"type":"null"}],"description":"Name of the shipping company, e.g., USPS, FedEx, DHL"},"ship_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ship Date"},"estimated_delivery_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated Delivery Date"},"delivery_status":{"anyOf":[{"$ref":"#/components/schemas/DeliveryStatus","maxLength":50,"minLength":1},{"type":"null"}],"description":"Current status of delivery, e.g., pending, in transit, delivered"},"last_updated":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Updated","description":"Timestamp of the last status update"}},"type":"object","required":["shipping_cost"],"title":"CashMailOrderData"},"CashoutMethodForeignValue":{"properties":{"value":{"type":"integer","minimum":0.0,"title":"Value","description":"Value of the redemption in the currency's smallest unit."},"currency":{"$ref":"#/components/schemas/RedemptionCurrency","description":"Supported Currencies for Foreign Redemptions\n\nAllowed values: \n - __USD__ *(USD)*: US Dollars. Smallest Unit: Cents.\n - __CAD__ *(CAD)*: Canadian Dollars. Smallest Unit: Cents.\n - __GBP__ *(GBP)*: British Pounds. Smallest Unit: Pence.\n - __EUR__ *(EUR)*: Euros. Smallest Unit: Cents.\n - __INR__ *(INR)*: Indian Rupees. Smallest Unit: Paise.\n - __AUD__ *(AUD)*: Australian Dollars. Smallest Unit: Cents.\n - __PLN__ *(PLN)*: Polish Zloty. Smallest Unit: Grosz.\n - __SEK__ *(SEK)*: Swedish Krona. Smallest Unit: Öre.\n - __SGD__ *(SGD)*: Singapore Dollars. Smallest Unit: Cents.\n - __MXN__ *(MXN)*: Mexican Pesos. Smallest Unit: Centavos."},"value_string":{"type":"string","title":"Value String","description":"A string representation of the value in the currency."}},"type":"object","required":["value","currency","value_string"],"title":"CashoutMethodForeignValue","description":"Shows the expected value of a redemption in a foreign currency.","example":{"currency":"CAD","value":"138","value_string":"$1.38 CAD"}},"CashoutMethodForeignValueResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout_method_value":{"$ref":"#/components/schemas/CashoutMethodForeignValue"}},"type":"object","required":["status","cashout_method_value"],"title":"CashoutMethodForeignValueResponse"},"CashoutMethodOut":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique ID for this cashout method"},"currency":{"type":"string","const":"USD","title":"Currency","description":"The currency of the cashout. Only USD is supported.","default":"USD"},"original_currency":{"anyOf":[{"$ref":"#/components/schemas/Currency"},{"type":"null"}],"description":"The base currency of the money paid out. This is used for e.g. sending an Amazon UK gift card"},"data":{"oneOf":[{"$ref":"#/components/schemas/PaypalCashoutMethodData"},{"$ref":"#/components/schemas/TangoCashoutMethodData"},{"$ref":"#/components/schemas/CashMailCashoutMethodData"},{"$ref":"#/components/schemas/AmtCashoutMethodData"}],"title":"Data","discriminator":{"propertyName":"type","mapping":{"AMT":"#/components/schemas/AmtCashoutMethodData","CASH_IN_MAIL":"#/components/schemas/CashMailCashoutMethodData","PAYPAL":"#/components/schemas/PaypalCashoutMethodData","TANGO":"#/components/schemas/TangoCashoutMethodData"}}},"description":{"type":"string","title":"Description","description":"The description of the cashout method.","default":""},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"Link to an image to display"},"max_value":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Value","description":"(In lowest unit of the original_currency), The maximum amount that can be cashed out in one transaction."},"min_value":{"type":"integer","minimum":0.0,"title":"Min Value","description":"(In lowest unit of the original_currency), The minimum amount that can be cashed out in one transaction."},"name":{"type":"string","title":"Name","description":"A descriptive name for the cashout method."},"type":{"$ref":"#/components/schemas/PayoutType","description":"The method in which the requested payout is delivered.\n\nAllowed values: \n - __PAYPAL__ *(PAYPAL)*: User is paid out to their personal PayPal email address\n - __TANGO__ *(TANGO)*: User is paid uut via a Tango Gift Card\n - __DWOLLA__ *(DWOLLA)*: DWOLLA\n - __ACH__ *(ACH)*: A payment is made to a bank account using ACH\n - __WIRE__ *(WIRE)*: A payment is made to a bank account using ACH\n - __CASH_IN_MAIL__ *(CASH_IN_MAIL)*: A payment is made in cash and mailed to the user.\n - __PRIZE__ *(PRIZE)*: A payment is made as a prize with some monetary value\n - __AMT__ *(AMT)*: This is used to designate either AMT_BONUS or AMT_HIT\n - __AMT_BONUS__ *(AMT_BONUS)*: Amazon Mechanical Turk as a Bonus\n - __AMT_ASSIGNMENT__ *(AMT_HIT)*: Amazon Mechanical Turk for a HIT"},"ext_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ext Id","description":"An external ID. Can be shown to a user to disambiguate a user's possibly multiple methods"},"usd_exchange_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Usd Exchange Rate"},"max_value_usd":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Value Usd","description":"(In lowest unit of USD), The maximum amount that can be cashed out in one transaction."},"min_value_usd":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Min Value Usd","description":"(In lowest unit of USD), The minimum amount that can be cashed out in one transaction."},"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"product_user_id":{"anyOf":[{"type":"string","maxLength":128,"minLength":3},{"type":"null"}],"title":"Product User Id","description":"A unique identifier for each user, which is set by the Supplier. It should not contain any sensitive informationlike email or names, and should avoid using anyincrementing values.","examples":["app-user-9329ebd"]}},"type":"object","required":["id","data","max_value","min_value","name","type"],"title":"CashoutMethodOut","example":{"bpid":"4a3ddfb747344bbc93efadf1c3a16e1a","currency":"USD","data":{"disclaimer":"...","terms":"..."},"description":"...","id":"941d489c3ce04eb39a0ddb7f8f75db74","image_url":"https://d30s7yzk2az89n.cloudfront.net/images/brands/b238587-1200w-326ppi.png","max_value":25000,"min_value":500,"name":"Visa® Prepaid Card USD","type":"TANGO"}},"CashoutMethodResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout_method":{"$ref":"#/components/schemas/CashoutMethodOut"}},"type":"object","required":["status","cashout_method"],"title":"CashoutMethodResponse"},"CashoutMethodsResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout_methods":{"items":{"$ref":"#/components/schemas/CashoutMethodOut"},"type":"array","title":"Cashout Methods"}},"type":"object","required":["status","cashout_methods"],"title":"CashoutMethodsResponse"},"CashoutRequestInfo":{"properties":{"id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Id","description":"Unique ID for this cashout. This may be NULL if the status is REJECTED or FAILED, which may happen if the request is invalid.","examples":["3ceb847aaf9f40f4bd15b2b5e083abf6"]},"description":{"type":"string","title":"Description","description":"This is the name of the cashout method.","examples":["Visa® Prepaid Card USD"]},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"status":{"anyOf":[{"$ref":"#/components/schemas/PayoutStatus"},{"type":"null"}],"description":" - `PENDING` = PENDING\n - `APPROVED` = APPROVED\n - `REJECTED` = REJECTED\n - `CANCELLED` = CANCELLED\n - `FAILED` = FAILED\n - `COMPLETE` = COMPLETE","default":"PENDING","examples":["PENDING"]},"transaction_info":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Transaction Info"}},"type":"object","required":["id","description"],"title":"CashoutRequestInfo","description":"See models.thl.payout: PayoutEvent. We've confused a CashOut and a\nPayout. This is used only in the API response."},"CashoutRequestResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout":{"$ref":"#/components/schemas/CashoutRequestInfo"}},"type":"object","required":["status","cashout"],"title":"CashoutRequestResponse"},"Category":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid","examples":["30fad401c93c438cae1cffecb046fd3e"]},"adwords_vertical_id":{"anyOf":[{"type":"string","maxLength":8},{"type":"null"}],"title":"Adwords Vertical Id"},"label":{"type":"string","maxLength":255,"title":"Label","examples":["Hair Loss"]},"path":{"type":"string","pattern":"^\\/.*[^\\/]$","title":"Path","examples":["/Beauty & Fitness/Hair Care/Hair Loss"]},"parent_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Parent Uuid","examples":["d52f3e2354ef434e9c89704fe1fb6018"]}},"type":"object","required":["uuid","label","path"],"title":"Category"},"CategoryAssociation":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"The category ID","examples":["c8642a1b86d9460cbe8f7e8ae6e56ee4"]},"label":{"type":"string","maxLength":255,"title":"Label","description":"The category label","examples":["People & Society"]},"adwords_id":{"anyOf":[{"type":"string","maxLength":8},{"type":"null"}],"title":"Adwords Id","examples":["14"]},"adwords_label":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Adwords Label","examples":["People & Society"]},"p":{"type":"number","maximum":1.0,"minimum":0.0,"title":"P","description":"The strength of the association of this bucketwith this category. Will sum to 1 within a bucket.","examples":[1.0]}},"type":"object","required":["id","label","p"],"title":"CategoryAssociation","description":"Used in an offerwall. Stores the association between a category\nand a bucket, with a score."},"ContestEndCondition":{"properties":{"target_entry_amount":{"anyOf":[{"anyOf":[{"type":"integer","minimum":0.0},{"type":"integer","exclusiveMinimum":0.0}],"ge":1},{"type":"null"}],"title":"Target Entry Amount","description":"The contest is over once this amount is reached. (sum of all entry amount)"},"ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ends At","description":"The contest is over at this time."}},"type":"object","title":"ContestEndCondition","description":"Defines the conditions to evaluate to determine when the contest is over.\nMultiple conditions can be set. The contest is over once ANY conditions are met."},"ContestEndReason":{"type":"string","enum":["cancelled","target_entry_amount","ends_at","max_winners"],"title":"ContestEndReason","description":"Defines why a contest ended"},"ContestEntryRule":{"properties":{"max_entry_amount_per_user":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Entry Amount Per User","description":"Maximum total value of entries per user"},"max_daily_entries_per_user":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Daily Entries Per User","description":"Maximum entries per user allowed per day for this contest"},"min_completes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Completes"},"min_membership_level":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Membership Level"},"id_verified":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Id Verified"}},"type":"object","title":"ContestEntryRule","description":"Defines rules the user must meet to be allowed to enter this contest\nOnly applies if the ContestType is ENTRY!"},"ContestEntryTrigger":{"type":"string","enum":["task_complete","task_attempt","referral"],"title":"ContestEntryTrigger","description":"Defines what action/event triggers a (possible) entry into the contest (automatically).\nThis only is valid on milestone contests"},"ContestPrize":{"properties":{"kind":{"$ref":"#/components/schemas/ContestPrizeKind","description":"\nAllowed values: \n - __physical__ *(PHYSICAL)*: A physical prize (e.g. a iPhone, cash in the mail, dinner with Max)\n - __promotion__ *(PROMOTION)*: A promotion is a temporary or special offer that provides extra value or benefits (e.g. 20% bonus on completes for the next 7 days)\n - __cash__ *(CASH)*: Money is deposited into user's virtual wallet"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"estimated_cash_value":{"type":"integer","minimum":0.0,"title":"Estimated Cash Value","description":"Estimated cash value of prize in USDCents"},"cash_amount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Cash Amount","description":"If the kind=ContestPrizeKind.CASH, this is the amount of the prize"},"promotion_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Promotion Id","description":"If the kind=ContestPrizeKind.PROMOTION, this is the promotion ID"},"leaderboard_rank":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Leaderboard Rank","description":"The prize is for achieving this rank in the associated leaderboard. The highest rank is 1."}},"type":"object","required":["kind","estimated_cash_value"],"title":"ContestPrize"},"ContestPrizeKind":{"type":"string","enum":["physical","promotion","cash"],"title":"ContestPrizeKind"},"ContestStatus":{"type":"string","enum":["active","completed","cancelled"],"title":"ContestStatus"},"ContestWinner":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this user won this prize"},"prize":{"$ref":"#/components/schemas/ContestPrize"},"awarded_cash_amount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Awarded Cash Amount","description":"The actual amount this user receives. For cash prizes, if there was a tie, this could be different from the prize amount."},"product_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product User Id","readOnly":true}},"type":"object","required":["prize","product_user_id"],"title":"ContestWinner","description":"In a Raffle, the ContestEntryType can be COUNT or CASH. In the CASH type, the unit\nof entry is 1 USDCent (one penny). Implicitly, each penny entered buys 1 entry\ninto the raffle, and one entry is randomly selected for each prize.\n\nA contest should have as many winners as there are prizes\nspecial case 1: there are fewer entries than prizes\nspecial case 2: leaderboard contest with ties"},"CountStat":{"properties":{"facet":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"number"}]},"propertyNames":{"enum":["country_iso","day","month"]},"type":"object","title":"Facet","description":"The grouping criteria","examples":[{"country_iso":"us"}]},"count":{"type":"integer","title":"Count","description":"The count value for the given metric and facet"}},"type":"object","required":["facet","count"],"title":"CountStat"},"CreateCashMailCashoutMethodRequest":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"Bpuid","description":"(product_user_id) The user to create this cashout method for.","examples":["app-user-9329ebd"]},"type":{"type":"string","const":"CASH_IN_MAIL","title":"Type","default":"CASH_IN_MAIL"},"delivery_address":{"$ref":"#/components/schemas/USDeliveryAddress","description":"Delivery address where payment should be sent"}},"type":"object","required":["bpuid","delivery_address"],"title":"CreateCashMailCashoutMethodRequest"},"CreateCashoutRequest":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"Bpuid","description":"(product_user_id) The user requesting a cashout.","examples":["app-user-9329ebd"]},"amount":{"type":"integer","exclusiveMinimum":0.0,"title":"Amount","description":"(USD cents) The amount requested for the cashout.","examples":[531]},"cashout_method_id":{"type":"string","maxLength":32,"minLength":32,"title":"Cashout Method Id","description":"Unique ID for the cashout method the cashout is being requested with.","examples":["941d489c3ce04eb39a0ddb7f8f75db74"]}},"type":"object","required":["bpuid","amount","cashout_method_id"],"title":"CreateCashoutRequest"},"CreatePayPalCashoutMethodRequest":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"Bpuid","description":"(product_user_id) The user to create this cashout method for.","examples":["app-user-9329ebd"]},"type":{"type":"string","const":"PAYPAL","title":"Type","default":"PAYPAL"},"email":{"type":"string","format":"email","title":"Email","description":"Email address of the paypal user","examples":["test@example.com"]}},"type":"object","required":["bpuid","email"],"title":"CreatePayPalCashoutMethodRequest"},"Currency":{"type":"string","enum":["USD","CAD","GBP","EUR","INR","AUD","PLN","SEK","SGD","MXN"],"title":"Currency"},"DeliveryStatus":{"type":"string","enum":["Pending","Shipped","In Transit","Out for Delivery","Delivered","Returned","Canceled","Failed Attempt","Lost"],"title":"DeliveryStatus"},"Direction":{"type":"integer","enum":[-1,1],"title":"Direction","description":"Entries on the debit side will increase debit normal accounts, while\nentries on the credit side will decrease them. Conversely, entries on\nthe credit side will increase credit normal accounts, while entries on\nthe debit side will decrease them.\n\nBy convention (?), the db will store transactions as debit-normal. For\na credit-normal account, we should flip the signs."},"DurationSummary":{"properties":{"min":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Min"},"max":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Max"},"mean":{"anyOf":[{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Mean"},"q1":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Q1"},"q2":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Q2"},"q3":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Q3"},"lower_whisker":{"type":"integer","title":"Lower Whisker","readOnly":true},"upper_whisker":{"type":"integer","title":"Upper Whisker","readOnly":true}},"type":"object","required":["min","max","q1","q2","q3","lower_whisker","upper_whisker"],"title":"DurationSummary","description":"Durations are in integer seconds.\nDescribes the statistical distribution of expected durations of tasks within this bucket.","examples":[{"max":1180,"mean":660,"min":112,"q1":457,"q2":650,"q3":1103}]},"EventEnvelope":{"properties":{"event_uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Event Uuid"},"event_type":{"$ref":"#/components/schemas/EventType"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"version":{"type":"integer","title":"Version","default":1},"product_user_id":{"anyOf":[{"type":"string","maxLength":128,"minLength":3},{"type":"null"}],"title":"Product User Id","description":"A unique identifier for each user. This is hidden unlessthe event is for the requesting user.","examples":["app-user-9329ebd"]},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"payload":{"oneOf":[{"$ref":"#/components/schemas/TaskEnterPayload"},{"$ref":"#/components/schemas/TaskFinishPayload"},{"$ref":"#/components/schemas/SessionEnterPayload"},{"$ref":"#/components/schemas/SessionFinishPayload"}],"title":"Payload","discriminator":{"propertyName":"event_type","mapping":{"session.enter":"#/components/schemas/SessionEnterPayload","session.finish":"#/components/schemas/SessionFinishPayload","task.enter":"#/components/schemas/TaskEnterPayload","task.finish":"#/components/schemas/TaskFinishPayload"}}}},"type":"object","required":["event_type","product_id","payload"],"title":"EventEnvelope"},"EventMessage":{"properties":{"kind":{"type":"string","const":"event","title":"Kind","default":"event"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"data":{"$ref":"#/components/schemas/EventEnvelope"}},"type":"object","required":["data"],"title":"EventMessage"},"EventType":{"type":"string","enum":["task.enter","task.finish","session.enter","session.finish","wallet.credit","wallet.debit","user.created","user.active"],"title":"EventType"},"GeoIPInformation":{"properties":{"geoname_id":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Geoname Id"},"continent_code":{"anyOf":[{"type":"string","maxLength":2},{"type":"null"}],"title":"Continent Code"},"continent_name":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Continent Name"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso","description":"The ISO code of the country associated with the IP address.","examples":["jm"]},"country_name":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Country Name"},"subdivision_1_iso":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Subdivision 1 Iso","description":"The ISO code of the primary subdivision (e.g., state or province)."},"subdivision_1_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Subdivision 1 Name","description":"The name of the primary subdivision (e.g., state or province)."},"subdivision_2_iso":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Subdivision 2 Iso","description":"The ISO code of the secondary subdivision (if applicable)."},"subdivision_2_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Subdivision 2 Name","description":"The name of the secondary subdivision (if applicable)."},"city_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"City Name","description":"The name of the city associated with the IP address.","examples":["Jamestown"]},"metro_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Metro Code"},"time_zone":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Time Zone","description":"The time zone associated with the geographical location.","examples":["Europe/Madrid"]},"is_in_european_union":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is In European Union"},"updated":{"type":"string","format":"date-time","title":"Updated"},"ip":{"type":"string","title":"Ip"},"registered_country_iso":{"anyOf":[{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},{"type":"null"}],"title":"Registered Country Iso","description":"The ISO code of the country where the IP address is registered.","examples":["sm"]},"is_anonymous":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Anonymous","description":"Indicates whether the IP address is associated with an anonymous source (e.g., VPN, proxy).","examples":[false]},"is_anonymous_vpn":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Anonymous Vpn"},"is_hosting_provider":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Hosting Provider"},"is_public_proxy":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Public Proxy"},"is_tor_exit_node":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Tor Exit Node"},"is_residential_proxy":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Residential Proxy"},"autonomous_system_number":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Autonomous System Number"},"autonomous_system_organization":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Autonomous System Organization"},"domain":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Domain"},"isp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Isp","description":"The Internet Service Provider associated with the IP address.","examples":["Comcast"]},"mobile_country_code":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Mobile Country Code"},"mobile_network_code":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Mobile Network Code"},"network":{"anyOf":[{"type":"string","maxLength":56},{"type":"null"}],"title":"Network"},"organization":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Organization"},"static_ip_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Static Ip Score","description":"A score indicating the likelihood that the IP address is static."},"user_type":{"anyOf":[{"$ref":"#/components/schemas/UserType"},{"type":"null"}],"description":"The type of user associated with the IP address (e.g., 'residential', 'business').","examples":["school"]},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code","description":"The postal code associated with the IP address.","examples":["13245"]},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude","description":"The latitude coordinate of the IP address location.","examples":[10.031844]},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude","description":"The longitude coordinate of the IP address location.","examples":[-20.111975]},"accuracy_radius":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Accuracy Radius","description":"The approximate radius of accuracy for the latitude and longitude, in kilometers.","examples":[167]}},"type":"object","required":["country_iso","ip"],"title":"GeoIPInformation"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IntegrationMode":{"type":"string","enum":["platform","pass_through"],"title":"IntegrationMode"},"Leaderboard":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique ID for this leaderboard","examples":["845b0074ad533df580ebb9c80cc3bce1"]},"name":{"type":"string","title":"Name","description":"Descriptive name for the leaderboard based on the board_code","examples":["Number of Completes"]},"board_code":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts","examples":["complete_count"]},"bpid":{"type":"string","maxLength":32,"minLength":32,"title":"Bpid","description":"product_id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"country_iso":{"type":"string","title":"Country Iso","description":"The country this leaderboard is for.","examples":["us"]},"freq":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00","examples":["daily"]},"timezone_name":{"type":"string","title":"Timezone Name","description":"The timezone for the requested country","examples":["America/New_York"]},"sort_order":{"type":"string","enum":["ascending","descending"],"title":"Sort Order","default":"descending"},"row_count":{"type":"integer","minimum":0.0,"title":"Row Count","description":"The total number of rows in the leaderboard.","examples":[2]},"rows":{"items":{"$ref":"#/components/schemas/LeaderboardRow"},"type":"array","title":"Rows","examples":[[{"bpuid":"app-user-9329ebd","rank":1,"value":4},{"bpuid":"app-user-7923skw","rank":2,"value":3}]]},"period_start_local":{"type":"string","format":"date-time","title":"Period Start Local","description":"The start of the time period covered by this board in local time, tz-aware","examples":["2024-07-12T00:00:00-04:00"]},"period_end_local":{"type":"string","format":"date-time","title":"Period End Local","description":"The end of the time period covered by this board in local time, tz-aware","examples":["2024-07-12T23:59:59.999999-04:00"]},"start_timestamp":{"type":"integer","title":"Start Timestamp","description":"(unix timestamp) The start time of the time range this leaderboard covers.","readOnly":true,"examples":[1720756800]},"end_timestamp":{"type":"integer","title":"End Timestamp","description":"(unix timestamp) The end time of the time range this leaderboard covers.","readOnly":true,"examples":[1720843199]},"utc_offset":{"type":"string","title":"Utc Offset","description":"The UTC offset for the timezone","readOnly":true,"examples":["-0400"]},"local_start_time":{"type":"string","title":"Local Start Time","description":"The start time of the time range this leaderboard covers (local time, in the leaderboard's timezone).","readOnly":true,"examples":["2024-07-12T00:00:00-04:00"]},"local_end_time":{"type":"string","title":"Local End Time","description":"The end time of the time range this leaderboard covers (local time, in the leaderboard's timezone).","readOnly":true,"examples":["2024-07-12T23:59:59.999999-04:00"]},"start_end_str":{"type":"string","title":"Start End Str","description":"A formatted string for time period covered by this leaderboard. Can be used to display to users.","readOnly":true,"examples":["2024-02-07 to 2024-02-08"]}},"type":"object","required":["board_code","bpid","country_iso","freq","row_count","period_start_local","start_timestamp","end_timestamp","utc_offset","local_start_time","local_end_time","start_end_str"],"title":"Leaderboard","description":"A leaderboard exists independently for each product_id in each country.\nEach country is associated with a single timezone. There is a daily,\nweekly, and monthly leaderboard."},"LeaderboardCode":{"type":"string","enum":["complete_count","largest_user_payout","sum_user_payout"],"title":"LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent."},"LeaderboardContestUserView":{"properties":{"name":{"type":"string","maxLength":128,"title":"Name","description":"Name of contest. Can be displayed to user."},"description":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Description","description":"Description of contest. Can be displayed to user."},"contest_type":{"type":"string","const":"leaderboard","title":"Contest Type","default":"leaderboard"},"end_condition":{"$ref":"#/components/schemas/ContestEndCondition"},"prizes":{"items":{"$ref":"#/components/schemas/ContestPrize"},"type":"array","minItems":1,"title":"Prizes"},"starts_at":{"type":"string","format":"date-time","title":"Starts At","description":"When the contest starts"},"terms_and_conditions":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Terms And Conditions"},"status":{"$ref":"#/components/schemas/ContestStatus","default":"active"},"country_isos":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Isos","description":"Contest is restricted to these countries. If null, all countries are allowed"},"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"Contest applies only to a single BP"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this contest was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When this contest was last modified. Does not include entries being created/modified"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the contest ended"},"end_reason":{"anyOf":[{"$ref":"#/components/schemas/ContestEndReason"},{"type":"null"}],"description":"The reason the contest ended"},"product_user_id":{"type":"string","title":"Product User Id"},"user_winnings":{"items":{"$ref":"#/components/schemas/ContestWinner"},"type":"array","title":"User Winnings","description":"The prizes won in this contest by the requested user"},"leaderboard_key":{"type":"string","title":"Leaderboard Key","description":"The specific leaderboard instance this contest is connected to","examples":["leaderboard:7a9d8d02334449ceb105764f77e1ba97:us:weekly:2025-05-26:complete_count"]},"tie_break_strategy":{"type":"string","const":"split_prize_pool","title":"Tie Break Strategy","default":"split_prize_pool"},"country_iso":{"type":"string","title":"Country Iso","readOnly":true},"user_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Rank","description":"The current rank of this user in this contest","readOnly":true}},"additionalProperties":false,"type":"object","required":["name","product_id","product_user_id","leaderboard_key","country_iso","user_rank"],"title":"LeaderboardContestUserView","example":{"contest_type":"leaderboard","country_iso":"us","country_isos":"us","created_at":"2026-02-18T07:03:18.635186Z","description":"$15 1st place, $10 2nd, $5 3rd place US weekly","end_condition":{"ends_at":"2025-06-02T05:29:59.999999Z"},"leaderboard_key":"leaderboard:1108d053e4fa47c5b0dbdcd03a7981e7:us:weekly:2025-05-26:complete_count","name":"Prizes for top survey takers this week","prizes":[{"cash_amount":1500,"estimated_cash_value":1500,"kind":"cash","leaderboard_rank":1,"name":"$15 Cash"},{"cash_amount":1000,"estimated_cash_value":1000,"kind":"cash","leaderboard_rank":2,"name":"$10 Cash"},{"cash_amount":500,"estimated_cash_value":500,"kind":"cash","leaderboard_rank":3,"name":"$5 Cash"}],"product_id":"1108d053e4fa47c5b0dbdcd03a7981e7","product_user_id":"test-user","starts_at":"2026-02-18T07:03:18.635162Z","status":"active","tie_break_strategy":"split_prize_pool","updated_at":"2026-02-18T07:03:18.635187Z","user_winnings":[],"uuid":"6adfa26d2b044cfa8bf0622041ee7c96"}},"LeaderboardFrequency":{"type":"string","enum":["daily","weekly","monthly"],"title":"LeaderboardFrequency","description":"The time period range for the leaderboard."},"LeaderboardResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"leaderboard":{"$ref":"#/components/schemas/Leaderboard"}},"type":"object","required":["status","leaderboard"],"title":"LeaderboardResponse"},"LeaderboardRow":{"properties":{"bpuid":{"type":"string","title":"Bpuid","description":"product_user_id","examples":["app-user-9329ebd"]},"rank":{"type":"integer","title":"Rank","description":"The numerical data ranks (1 through n) of the values. Ties are ranked using the lowest rank in the group.","examples":[1]},"value":{"type":"integer","title":"Value","description":"The value. The meaning of the value is dependent on the LeaderboardCode.","examples":[7]}},"type":"object","required":["bpuid","rank","value"],"title":"LeaderboardRow"},"LeaderboardWinner":{"properties":{"rank":{"type":"integer","title":"Rank","description":"The user's final rank in the leaderboard","examples":[1]},"freq":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00","examples":["daily"]},"board_code":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts","examples":["complete_count"]},"country_iso":{"type":"string","title":"Country Iso","description":"The country this leaderboard is for.","examples":["us"]},"issued":{"type":"string","format":"date-time","title":"Issued","description":"When the prize was issued.","examples":["2022-10-17T05:59:14.570231Z"]},"bpuid":{"type":"string","title":"Bpuid","description":"product_user_id","examples":["app-user-9329ebd"]},"description":{"type":"string","title":"Description","examples":["Bonus for daily contest"]},"amount":{"type":"integer","title":"Amount","description":"(USD cents) The reward amount","examples":[1000]},"amount_str":{"type":"string","title":"Amount Str","description":"The amount as a formatted string in USD. Can be displayed to the user.","examples":["$10.00"]},"contest_start":{"type":"string","format":"date-time","title":"Contest Start","description":"When the leaderboard started","examples":["2022-10-16T04:00:00Z"]},"contest_end":{"type":"string","format":"date-time","title":"Contest End","description":"When the leaderboard ended","examples":["2022-10-17T04:00:00Z"]}},"type":"object","required":["rank","freq","board_code","country_iso","issued","bpuid","description","amount","amount_str","contest_start","contest_end"],"title":"LeaderboardWinner"},"LeaderboardWinnerResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"winners":{"items":{"$ref":"#/components/schemas/LeaderboardWinner"},"type":"array","title":"Winners"}},"type":"object","required":["status"],"title":"LeaderboardWinnerResponse"},"LedgerAccount":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid","description":"A unique identifier for this Ledger Account","examples":["c3c3566b5b1b4961b63a5670a2dc923d"]},"display_name":{"type":"string","maxLength":64,"title":"Display Name","description":"Human-readable description of the Ledger Account","examples":["BP Wallet c3c3566b5b1b4961b63a5670a2dc923d"]},"qualified_name":{"type":"string","maxLength":255,"title":"Qualified Name"},"account_type":{"$ref":"#/components/schemas/AccountType","description":" - `bp_commission` = BP_COMMISSION\n - `bp_wallet` = BP_WALLET\n - `user_wallet` = USER_WALLET\n - `cash` = CASH\n - `revenue` = REVENUE\n - `expense` = EXPENSE\n - `contest_wallet` = CONTEST_WALLET\n - `credit_line` = CREDIT_LINE\n - `wa_wallet` = WA_WALLET\n - `wa_budget_pool` = WA_BUDGET_POOL\n - `wa_held` = WA_HELD\n - `wa_credit_line` = WA_CREDIT_LINE","examples":["bp_wallet"]},"normal_balance":{"$ref":"#/components/schemas/Direction","description":" - `-1` = CREDIT\n - `1` = DEBIT"},"reference_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Type"},"reference_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Reference Uuid","description":"The associated Product ID or other parent account thatthis Ledger Account is intended to track transactions for.If Wallet mode is enabled, this can also handle trackingindividual users.","examples":["61dd0b086fd048518762757612b4a6d3"]},"currency":{"type":"string","maxLength":32,"title":"Currency","description":"GRL's Ledger system allows tracking of transactions inany currency possible. This is useful for trackingpoints, stars, coins, or any other currency that may beused in a Supplier's platform.","default":"USD"}},"type":"object","required":["display_name","qualified_name","account_type","normal_balance"],"title":"LedgerAccount"},"LedgerEntry":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Id"},"direction":{"$ref":"#/components/schemas/Direction"},"account_uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Account Uuid"},"amount":{"type":"integer","exclusiveMaximum":9.223372036854776e+18,"exclusiveMinimum":0.0,"title":"Amount","description":"The USDCent amount. A LedgerEntry cannot be made for0 USDCent and it cannot be negative.","examples":[531]},"transaction_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Transaction Id"}},"type":"object","required":["direction","account_uuid","amount"],"title":"LedgerEntry"},"LedgerTransaction":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Id"},"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction (TX) was created into the database.This does not represent the exact time for any actionwhich may be responsible for this Transaction (TX), and TX timestamps will likely be a few milliseconds delayed"},"ext_description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Ext Description"},"tag":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Tag"},"metadata":{"additionalProperties":{"type":"string"},"type":"object","title":"Metadata"},"entries":{"items":{"$ref":"#/components/schemas/LedgerEntry"},"type":"array","title":"Entries","description":"A Transaction (TX) is composed of multiple Entry events."}},"additionalProperties":false,"type":"object","title":"LedgerTransaction"},"MarketProfileKnowledge":{"properties":{"source":{"$ref":"#/components/schemas/Source","maxLength":16,"description":"Marketplace this question is from"},"question_id":{"type":"string","title":"Question Id","examples":["gender","1843","gender_plus"]},"answer":{"items":{"type":"string"},"type":"array","title":"Answer","examples":[["male"],["7657644"],["1"]]},"created":{"type":"string","format":"date-time","title":"Created","description":"When the User submitted this Profiling data"}},"type":"object","required":["source","question_id","created"],"title":"MarketProfileKnowledge","description":"This is used solely in API responses, so it is simplified."},"MarketplaceBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"x":{"type":"integer","minimum":0.0,"title":"X","description":"For UI. Provides a dimensionality position for the bucket on the x-axis.","default":0,"examples":[0,1,2]},"y":{"type":"integer","minimum":0.0,"title":"Y","description":"For UI. Provides a dimensionality position for the bucket on the y-axis.","default":0,"examples":[0,1,2]},"name":{"type":"string","title":"Name","description":"Currently unused. Will always return empty string","default":""},"description":{"type":"string","title":"Description","description":"Currently unused. Will always return empty string","default":""},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"duration":{"$ref":"#/components/schemas/DurationSummary"},"payout":{"$ref":"#/components/schemas/PayoutSummary"},"source":{"type":"string","enum":["innovate","dynata","schlesinger","purespectrum","morning","pollfish","precision","repdata","prodege"],"title":"Source","description":"this is the source of the contents","examples":["pollfish"]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","duration","payout","source"],"title":"MarketplaceBucket"},"MarketplaceInventorySummary":{"properties":{"live_tasks":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Live Tasks","description":"The count of tasks that are currently live"},"live_gen_pop_tasks":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Live Gen Pop Tasks","description":"The count of gen-pop tasks that are currently live"},"tasks_created":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Tasks Created","description":"The count of tasks created"},"required_finishes":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Required Finishes","description":"Number of finishes needed across all live tasks"},"payout":{"items":{"$ref":"#/components/schemas/StatisticalSummaryStat"},"type":"array","title":"Payout","description":"The distribution of payouts for all live tasks"},"expected_duration":{"items":{"$ref":"#/components/schemas/StatisticalSummaryStat"},"type":"array","title":"Expected Duration","description":"The distribution of expected durations for all live tasks"},"required_finishes_per_task":{"items":{"$ref":"#/components/schemas/StatisticalSummaryStat"},"type":"array","title":"Required Finishes Per Task","description":"The distribution of required finishes on all live tasks"}},"type":"object","title":"MarketplaceInventorySummary"},"MarketplaceOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/MarketplaceBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"MarketplaceOfferwall","description":"Returns buckets grouped by marketplace, one per marketplace, with the\ntasks ordered by quality.\n\nOfferwall code: `5fa23085`"},"MarketplaceOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/MarketplaceOfferwall"}},"type":"object","required":["info","offerwall"],"title":"MarketplaceOfferwallResponse"},"MarketplaceSummary":{"properties":{"inventory":{"$ref":"#/components/schemas/MarketplaceInventorySummary","description":"Inventory of the marketplace"},"user_activity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Activity","description":"User activity of the marketplace"}},"type":"object","required":["inventory"],"title":"MarketplaceSummary"},"MaxGaugeBySource":{"properties":{"value":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Value"},"by_source":{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object","title":"By Source"}},"type":"object","title":"MaxGaugeBySource"},"MilestoneContestEndCondition":{"properties":{"max_winners":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Winners","description":"The contest will end once this many users have won (i.e. reachedthe milestone)."},"ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ends At","description":"The Contest is over at the ends_at time."}},"type":"object","title":"MilestoneContestEndCondition","description":"Defines the conditions to evaluate to determine when the contest is over.\nMultiple conditions can be set. The contest is over once ANY conditions are met."},"MilestoneUserView":{"properties":{"target_amount":{"type":"integer","exclusiveMinimum":0.0,"title":"Target Amount","description":"Each user 'wins' (receives prizes) once this target amount is reached."},"entry_trigger":{"anyOf":[{"$ref":"#/components/schemas/ContestEntryTrigger"},{"type":"null"}],"description":"What user action triggers an entry automatically."},"valid_for":{"anyOf":[{"type":"string","format":"duration"},{"type":"null"}],"title":"Valid For","description":"The time after valid_for_event for which the contest is open"},"valid_for_event":{"anyOf":[{"type":"string","const":"signup"},{"type":"null"}],"title":"Valid For Event"},"name":{"type":"string","maxLength":128,"title":"Name","description":"Name of contest. Can be displayed to user."},"description":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Description","description":"Description of contest. Can be displayed to user."},"contest_type":{"type":"string","const":"milestone","title":"Contest Type","default":"milestone"},"end_condition":{"$ref":"#/components/schemas/MilestoneContestEndCondition"},"prizes":{"items":{"$ref":"#/components/schemas/ContestPrize"},"type":"array","minItems":1,"title":"Prizes"},"starts_at":{"type":"string","format":"date-time","title":"Starts At","description":"When the contest starts"},"terms_and_conditions":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Terms And Conditions"},"status":{"$ref":"#/components/schemas/ContestStatus","default":"active"},"country_isos":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Isos","description":"Contest is restricted to these countries. If null, all countries are allowed"},"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"Contest applies only to a single BP"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this contest was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When this contest was last modified. Does not include entries being created/modified"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the contest ended"},"end_reason":{"anyOf":[{"$ref":"#/components/schemas/ContestEndReason"},{"type":"null"}],"description":"The reason the contest ended"},"product_user_id":{"type":"string","title":"Product User Id"},"user_winnings":{"items":{"$ref":"#/components/schemas/ContestWinner"},"type":"array","title":"User Winnings","description":"The prizes won in this contest by the requested user"},"entry_type":{"type":"string","const":"count","title":"Entry Type","default":"count"},"win_count":{"type":"integer","title":"Win Count","description":"The number of times the milestone has been reached.","default":0},"user_amount":{"type":"integer","title":"User Amount","description":"The total amount for this user for this contest"}},"additionalProperties":false,"type":"object","required":["target_amount","name","end_condition","product_id","product_user_id","user_amount"],"title":"MilestoneUserView","example":{"contest_type":"milestone","created_at":"2025-06-12T21:12:58.061205Z","description":"Only valid for the first 50 users","end_condition":{"max_winners":50},"entry_trigger":"task_complete","entry_type":"count","name":"Win a 50% bonus for 7 days and a $5 bonus after your first 10 completes!","prizes":[{"estimated_cash_value":0,"kind":"promotion","name":"50% bonus on completes for 7 days"},{"cash_amount":500,"estimated_cash_value":500,"kind":"cash","name":"$5.00 Bonus"}],"product_id":"1108d053e4fa47c5b0dbdcd03a7981e7","product_user_id":"test-user","starts_at":"2025-06-12T21:12:58.061170Z","status":"active","target_amount":10,"terms_and_conditions":"https://www.example.com/","updated_at":"2025-06-12T21:12:58.061205Z","user_amount":8,"user_winnings":[],"uuid":"747fe3b709ae460e816821dcb81aebb9","win_count":12}},"OfferWallCategoryRequest":{"properties":{"adwords_category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Adwords Category","examples":[["45","65"]]},"category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Category","examples":[["98c137e4e90a4d92ac6c00e523eb1b50"]]},"exclude_adwords_category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exclude Adwords Category","examples":[["1558"]]},"exclude_category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exclude Category","examples":[["21536f160f784189be6194ca894f3a65","7aa8bf4e71a84dc3b2035f93f9f9c77e"]]}},"type":"object","title":"OfferWallCategoryRequest"},"OfferWallInfo":{"properties":{"success":{"type":"boolean","title":"Success"}},"type":"object","required":["success"],"title":"OfferWallInfo"},"OfferWallRequestYieldmanParams":{"properties":{"conversion_factor_adj":{"type":"number","title":"Conversion Factor Adj","description":"Centered around 0. Higher results in higher weight given to conversion (in the scoring function)","default":0.0},"dropoffrate_factor_adj":{"type":"number","title":"Dropoffrate Factor Adj","description":"Centered around 0. Higher results in higher penalty given to dropoffs (in the scoring function)","default":0.0},"longfail_factor_adj":{"type":"number","title":"Longfail Factor Adj","description":"Centered around 0. Higher results in higher penalty given to long fail (in the scoring function)","default":0.0},"recon_factor_adj":{"type":"number","title":"Recon Factor Adj","description":"Centered around 0. Higher results in higher penalty given to recons (in the scoring function)","default":0.0},"recon_likelihood_max":{"type":"number","title":"Recon Likelihood Max","description":"Tolerance for recon likelihood (0 to 1)","default":0.8}},"type":"object","title":"OfferWallRequestYieldmanParams"},"OfferwallConfig":{"properties":{},"type":"object","title":"OfferwallConfig"},"OfferwallReason":{"type":"string","enum":["USER_BLOCKED","HIGH_RECON_RATE","UNCOMMON_DEMOGRAPHICS","UNDER_MINIMUM_AGE","EXHAUSTED_HIGH_VALUE_SUPPLY","ALL_ELIGIBLE_ATTEMPTED","LOW_CURRENT_SUPPLY"],"title":"OfferwallReason"},"OneShotOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/OneShotOfferwallBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"OneShotOfferwall","description":"Each bucket has only 1 single task, and only basic info is returned\n about each bucket.\n\nOfferwall code: `6f27b1ae`"},"OneShotOfferwallBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"duration":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Duration","description":"The bucket's expected duration, in seconds"},"min_payout":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Min Payout","description":"The bucket's min payout, in usd cents"}},"additionalProperties":false,"type":"object","required":["id","uri","duration","min_payout"],"title":"OneShotOfferwallBucket"},"OneShotOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/OneShotOfferwall"}},"type":"object","required":["info","offerwall"],"title":"OneShotOfferwallResponse"},"POPFinancial":{"properties":{"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["3d350f18fdfe41f5a0e95b5e1c28733e"]},"time":{"type":"string","format":"date-time","title":"Time","description":"The starting time block for the respective 'Period' thatthis grouping is on. The `time` could be the start of a 1 minute or 1 hour block for example."},"payout":{"type":"integer","minimum":0.0,"title":"Payout","description":"The total amount (in USD cents) that the Brokerage Producthas earned within a respective time period.","default":0,"examples":[8359]},"adjustment":{"type":"integer","title":"Adjustment","description":"The total amount (in USD cents) that the Brokerage Producthas had adjusted within a respective time period. Most ofthe time, this will be negative due to Complete to Incomplete reconciliations. However, it can also be positive due to Incomplete to Complete adjustments.","examples":[1911]},"adjustment_types":{"items":{"$ref":"#/components/schemas/AdjustmentType"},"type":"array","title":"Adjustment Types"},"expense":{"type":"integer","title":"Expense","description":"For Product accounts that are setup with Respondent payouts,competitions, user bonuses, or other associated 'costs', thoseexpenses are accounted for here. This will be negative forthose types of costs."},"net":{"type":"integer","title":"Net","description":"This is the sum of the Payout total, Adjustment and any Expenses total. It can be positive or negative for any specific time period.","examples":[10270]},"payment":{"type":"integer","title":"Payment","description":"Any ACH or Wire amount that was issued between GRL and the Supplier.","examples":[3408288]}},"type":"object","required":["time","adjustment","adjustment_types","expense","net","payment"],"title":"POPFinancial","description":"We can't use our USDCent class in here because aside from it not\n supporting negative values for our adjustments, FastAPI also\n complains because it doesn't know how to generate documentation\n for it. - Max 2024-06-25"},"PatternValidation":{"properties":{"message":{"type":"string","title":"Message","description":"Message to display if validation fails"},"pattern":{"type":"string","title":"Pattern","description":"Regex string to validate. min_length and max_length are checked separately, even if they are part of the regex."}},"type":"object","required":["message","pattern"],"title":"PatternValidation"},"PayoutConfig":{"properties":{"payout_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]},"payout_transformation":{"anyOf":[{"$ref":"#/components/schemas/PayoutTransformation"},{"type":"null"}],"description":"How the BP's payout is converted to the User's payout"}},"type":"object","title":"PayoutConfig","description":"Store configuration related to payouts, payout transformation, and user\npayout formatting."},"PayoutStatus":{"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED","FAILED","COMPLETE"],"title":"PayoutStatus","description":"The max size of the db field that holds this value is 20, so please\ndon't add new values longer than that!"},"PayoutSummary":{"properties":{"min":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Min"},"max":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Max"},"mean":{"anyOf":[{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Mean"},"q1":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Q1"},"q2":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Q2"},"q3":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Q3"},"lower_whisker":{"type":"integer","title":"Lower Whisker","readOnly":true},"upper_whisker":{"type":"integer","title":"Upper Whisker","readOnly":true}},"type":"object","required":["min","max","q1","q2","q3","lower_whisker","upper_whisker"],"title":"PayoutSummary","description":"Payouts are in Integer USD Cents","examples":[{"max":132,"min":14,"q1":45,"q2":68,"q3":124}]},"PayoutTransformation":{"properties":{"f":{"type":"string","enum":["payout_transformation_percent","payout_transformation_amt"],"title":"F","description":"The name of the transformation function to use."},"kwargs":{"anyOf":[{"$ref":"#/components/schemas/PayoutTransformationPercentArgs"},{"type":"null"}],"description":"The kwargs to pass to the transformation function.","examples":[{"max_payout":"5.00","pct":0.5}]}},"type":"object","required":["f"],"title":"PayoutTransformation","description":"This model describe how the bp_payout is converted to the user_payout.\nIf None, the user_payout is None.\n\nIf the user_wallet_enabled is `False`, the user_payout is used to\n 1) know how to transform the expected payouts for offerwall buckets\n (if min_payout is requested, this is based on the user_payout)\n 2) show the user (using the payout_format) how much they made (in\n the Task Status Response).\nIf the user_wallet_enabled is `True`, then in addition to the above, the\n user_payout is the amount actually paid to the user's wallet."},"PayoutTransformationPercentArgs":{"properties":{"pct":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Pct","description":"The percentage of the bp_payout to pay the user","examples":[0.5]},"min_payout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Payout","description":"The minimum amount paid for a complete. Note: This does not check that the actual payout was at least this amount.","examples":["0.50"]},"max_payout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Max Payout","description":"The maximum amount paid for a complete","examples":["5.00"]}},"type":"object","required":["pct"],"title":"PayoutTransformationPercentArgs"},"PayoutType":{"type":"string","enum":["PAYPAL","TANGO","DWOLLA","ACH","WIRE","CASH_IN_MAIL","PRIZE","AMT","AMT_BONUS","AMT_ASSIGNMENT","AMT_ASSIGNMENT"],"title":"PayoutType","description":"The method in which the requested payout is delivered."},"PaypalCashoutMethodData":{"properties":{"type":{"type":"string","const":"PAYPAL","title":"Type","default":"PAYPAL"},"email":{"type":"string","format":"email","title":"Email","description":"Email address of the paypal user","examples":["test@example.com"]}},"type":"object","required":["email"],"title":"PaypalCashoutMethodData"},"PingMessage":{"properties":{"kind":{"type":"string","const":"ping","title":"Kind","default":"ping"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","title":"PingMessage"},"PongMessage":{"properties":{"kind":{"type":"string","const":"pong","title":"Kind","default":"pong"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","title":"PongMessage"},"Product":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier of the Brokerage Product","examples":["1108d053e4fa47c5b0dbdcd03a7981e7"]},"name":{"type":"string","maxLength":255,"minLength":3,"title":"Name","description":"Name of the Brokerage Product. Must be unique within a Team","examples":["Website ABC"]},"enabled":{"type":"boolean","title":"Enabled","description":"This is only used to hard block a Product in order to immediately & safely protect against fraud entrances.","default":true},"payments_enabled":{"type":"boolean","title":"Payments Enabled","description":"This is only to determine if ACH or Wire payments should be made to the Produce.","default":true},"created":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created","description":"When the Product was created, this does necessarily mean it started to retrieve traffic at that time."},"team_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Team Id","description":"The organization (group of generalresearch.com admin accounts) that is allowed to modify and manage thisProduct","examples":["b96c1209cf4a4baaa27d38082421a039"]},"business_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Business Id","description":"The legal business entity or individual that is responsible for this account, and that receive SupplierPayments for this Product's activity.","examples":["9b1d71aab7b84112ac936a574fadd5d6"]},"tags":{"items":{"$ref":"#/components/schemas/SupplierTag"},"type":"array","uniqueItems":true,"title":"Tags","description":"Tags which are used to annotate supplier traffic"},"commission_pct":{"type":"string","title":"Commission Pct","default":"0.05"},"redirect_url":{"type":"string","title":"Redirect Url","description":"Where to redirect the user after finishing a session. When a user get redirected back to the supplier, a query param will be added with the name 'tsid', and the value of the TSID for the session. For example: callback_uri: 'https://www.example.com/test/?a=1&b=2' might result in the user getting redirected to: 'https://www.example.com/grl-callback/?a=1&b=2&tsid=c6ab6ba1e75b44e2bf5aab00fc68e3b7'.","examples":["https://www.example.com/grl-callback/?a=1&b=2"]},"harmonizer_domain":{"type":"string","title":"Harmonizer Domain","description":"This is the domain that is used for the GRS (General Research Survey) platform. This is a simple javascript application which may profile the respondent for anyprofiling questions, along with collecting any browserbased security information. The value is a scheme+domain only (no path).","default":"https://profile.generalresearch.com/"},"sources_config":{"anyOf":[{"$ref":"#/components/schemas/SourcesConfig"},{"$ref":"#/components/schemas/SupplyConfig"}],"title":"Sources Config"},"session_config":{"$ref":"#/components/schemas/SessionConfig"},"payout_config":{"$ref":"#/components/schemas/PayoutConfig"},"user_wallet_config":{"$ref":"#/components/schemas/UserWalletConfig"},"user_create_config":{"$ref":"#/components/schemas/UserCreateConfig"},"offerwall_config":{"$ref":"#/components/schemas/OfferwallConfig"},"profiling_config":{"$ref":"#/components/schemas/ProfilingConfig"},"user_health_config":{"$ref":"#/components/schemas/UserHealthConfig"},"yield_man_config":{"$ref":"#/components/schemas/YieldManConfig"},"balance":{"anyOf":[{"$ref":"#/components/schemas/ProductBalances"},{"type":"null"}],"description":"Product Balance"},"payouts_total_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payouts Total Str"},"payouts_total":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Payouts Total"},"payouts":{"anyOf":[{"items":{"$ref":"#/components/schemas/BrokerageProductPayoutEvent"},"type":"array"},{"type":"null"}],"title":"Payouts","description":"Product Payouts. These are the ACH or Wire payments that were sent to theBusiness on behalf of this specific Product"},"pop_financial":{"anyOf":[{"items":{"$ref":"#/components/schemas/POPFinancial"},"type":"array"},{"type":"null"}],"title":"Pop Financial"},"bp_account":{"anyOf":[{"$ref":"#/components/schemas/LedgerAccount"},{"type":"null"}]},"user_wallet":{"$ref":"#/components/schemas/UserWalletConfig","readOnly":true}},"type":"object","required":["name","redirect_url","user_wallet"],"title":"Product"},"ProductBalances":{"properties":{"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["7bb8fd6215c1451399ac80a4a44d4044"]},"last_event":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Event"},"bp_payment_credit":{"type":"integer","minimum":0.0,"title":"Bp Payment Credit","description":"The total amount that has been earned by the Task completes, for this Brokerage Product account.","default":0,"examples":[18837]},"adjustment_credit":{"type":"integer","minimum":0.0,"title":"Adjustment Credit","description":"Positive reconciliations issued back to the Brokerage Product account.","default":0,"examples":[2]},"adjustment_debit":{"type":"integer","minimum":0.0,"title":"Adjustment Debit","description":"Negative reconciliations for any Task completes","default":0,"examples":[753]},"supplier_credit":{"type":"integer","minimum":0.0,"title":"Supplier Credit","description":"ACH or Wire amounts issued to GRL from a Supplier to recoup for a negative Brokerage Product balance","default":0,"examples":[0]},"supplier_debit":{"type":"integer","minimum":0.0,"title":"Supplier Debit","description":"ACH or Wire amounts sent to a Supplier","default":0,"examples":[10000]},"user_bonus_credit":{"type":"integer","minimum":0.0,"title":"User Bonus Credit","description":"If a respondent ever pays back an product account.","default":0,"examples":[0]},"user_bonus_debit":{"type":"integer","minimum":0.0,"title":"User Bonus Debit","description":"Pay a user into their wallet balance. There is no fee here. There is only a fee when the user requests a payout.The bonus could be as a bribe, winnings for a contest, leaderboard, etc.","default":0,"examples":[2745]},"issued_payment":{"type":"integer","minimum":0.0,"title":"Issued Payment","description":"This is the amount that we decide to credit as havingtaken from this Product. If there is any amount not issuedit is summed up over the Business to offset any negativebalances elsewhere.","default":0},"payout":{"type":"integer","title":"Task Payouts","description":"The sum amount of all Task payouts","readOnly":true,"examples":[18837]},"payout_usd_str":{"type":"string","title":"Task Payouts USD Str","readOnly":true,"examples":["$18,837.00"]},"adjustment":{"type":"integer","title":"Task Adjustments","description":"The sum amount of all Task Adjustments","readOnly":true,"examples":[-751]},"expense":{"type":"integer","title":"Product Expenses","description":"The sum amount of any associated Product Expenses (eg: user bonuses)","readOnly":true,"examples":[-2745]},"net":{"type":"integer","title":"Net Earnings","description":"The Product's Net Earnings which is equal to the totalamount of Task Payouts, with Task Adjustments and anyProduct Expenses deducted. This can be positive ornegative.","readOnly":true,"examples":[15341]},"payment":{"type":"integer","minimum":0.0,"title":"Supplier Payments","description":"The sum amount of all Supplier Payments (eg ACH or Wire transfers)","readOnly":true,"examples":[10000]},"payment_usd_str":{"type":"string","title":"Supplier Payments","readOnly":true,"examples":["$10,000"]},"balance":{"type":"integer","title":"Product Balance","description":"The Product's Balance which is equal to the Product's Netamount with already issued Supplier Payments deducted. This can be positive or negative.","readOnly":true,"examples":[5341]},"retainer":{"type":"integer","minimum":0.0,"title":"Smart Retainer","description":"The Smart Retainer is an about of money that is held byGRL to account for any Task Adjustments that may occurin the future. The amount will always be positive, andif the Product's balance is negative, the retainer will be $0.00 as the Product is not eligible for any SupplierPayments either way.","readOnly":true,"examples":[1335]},"retainer_usd_str":{"type":"string","title":"Smart Retainer USD Str","readOnly":true,"examples":["$1,335.00"]},"available_balance":{"type":"integer","minimum":0.0,"title":"Available Balance","description":"The Available Balance is the amount that is currently, andimmediately available for withdraw from the Supplier'sbalance. Supplier Payments are made every Friday for Businesses with an ACH connected Bank Account to GRL, while a Business that requires an International Wire are issued on the last Friday of every Month.","readOnly":true,"examples":[4006]},"available_balance_usd_str":{"type":"string","title":"Available Balance USD Str","readOnly":true,"examples":["$4,006.00"]},"recoup":{"type":"integer","minimum":0.0,"title":"Recoup","readOnly":true,"examples":[282]},"recoup_usd_str":{"type":"string","title":"Recoup Str","readOnly":true,"examples":["$2.04"]},"adjustment_percent":{"type":"number","title":"Adjustment Percentage","description":"The percentage of USDCent value that has been adjustedover all time for this Product.","readOnly":true,"examples":[0.064938]}},"type":"object","required":["payout","payout_usd_str","adjustment","expense","net","payment","payment_usd_str","balance","retainer","retainer_usd_str","available_balance","available_balance_usd_str","recoup","recoup_usd_str","adjustment_percent"],"title":"ProductBalances"},"ProfilingConfig":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"If False, the harmonizer/profiling system is not used at all. This should never be False unless special circumstances","default":true},"grs_enabled":{"type":"boolean","title":"Grs Enabled","description":"If grs_enabled is False, and is_grs is passed in the profiling-questions call, \n then don't actually return any questions. This allows a client to hit the endpoint with no limit \n and still get questions. In effect, this means that we'll redirect the user through the GRS\n system but won't present them any questions.","default":true},"n_questions":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"N Questions","description":"Use to hard code the number of questions to ask. None means use default algorithm."},"max_questions":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Questions","description":"The max number of questions we would ask in a session","default":10},"avg_question_count":{"type":"number","exclusiveMinimum":0.0,"title":"Avg Question Count","description":"The average number of questions to ask in a session","default":5},"task_injection_freq_mult":{"type":"number","exclusiveMinimum":0.0,"title":"Task Injection Freq Mult","description":"Scale how frequently we inject profiling questions, relative to the default.1 is default, 2 is twice as often. 10 means always. 0.5 half as often","default":1},"non_us_mult":{"type":"number","exclusiveMinimum":0.0,"title":"Non Us Mult","description":"Non-us multiplier, used to increase freq and length of profilers in all non-us countries.This value is multiplied by task_injection_freq_mult and avg_question_count.","default":2},"hidden_questions_expiration_hours":{"type":"integer","exclusiveMinimum":0.0,"title":"Hidden Questions Expiration Hours","description":"How frequently we should refresh hidden questions","default":168}},"type":"object","title":"ProfilingConfig"},"ProfilingInfoResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"profiling-info":{"items":{"$ref":"#/components/schemas/UpkProperty"},"type":"array","title":"Profiling-Info"}},"type":"object","required":["status","profiling-info"],"title":"ProfilingInfoResponse"},"PropertyType":{"type":"string","enum":["i","n","x"],"title":"PropertyType"},"RaffleUserView":{"properties":{"name":{"type":"string","maxLength":128,"title":"Name","description":"Name of contest. Can be displayed to user."},"description":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Description","description":"Description of contest. Can be displayed to user."},"contest_type":{"type":"string","const":"raffle","title":"Contest Type","default":"raffle"},"end_condition":{"$ref":"#/components/schemas/ContestEndCondition"},"prizes":{"items":{"$ref":"#/components/schemas/ContestPrize"},"type":"array","minItems":1,"title":"Prizes"},"starts_at":{"type":"string","format":"date-time","title":"Starts At","description":"When the contest starts"},"terms_and_conditions":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Terms And Conditions"},"status":{"$ref":"#/components/schemas/ContestStatus","default":"active"},"country_isos":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Isos","description":"Contest is restricted to these countries. If null, all countries are allowed"},"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"Contest applies only to a single BP"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this contest was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When this contest was last modified. Does not include entries being created/modified"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the contest ended"},"end_reason":{"anyOf":[{"$ref":"#/components/schemas/ContestEndReason"},{"type":"null"}],"description":"The reason the contest ended"},"product_user_id":{"type":"string","title":"Product User Id"},"user_winnings":{"items":{"$ref":"#/components/schemas/ContestWinner"},"type":"array","title":"User Winnings","description":"The prizes won in this contest by the requested user"},"entry_type":{"type":"string","const":"cash","title":"Entry Type","default":"cash"},"entry_rule":{"$ref":"#/components/schemas/ContestEntryRule"},"current_amount":{"anyOf":[{"type":"integer"},{"type":"integer","minimum":0.0}],"title":"Current Amount","description":"Sum of all entry amounts","default":0},"current_participants":{"type":"integer","title":"Current Participants","description":"Count of unique participants","default":0},"user_amount":{"anyOf":[{"type":"integer"},{"type":"integer","minimum":0.0}],"title":"User Amount","description":"The total amount this user has entered"},"user_amount_today":{"anyOf":[{"type":"integer"},{"type":"integer","minimum":0.0}],"title":"User Amount Today","description":"The total amount this user has entered in the past 24 hours"},"current_win_probability":{"type":"number","title":"Current Win Probability","description":"Probability of this user winning 1 or more prizes, if the contestended right now","readOnly":true},"projected_win_probability":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Projected Win Probability","description":"Probability of this user winning 1 or more prizes, once the contestis projected to end. This value is only calculated if the contest has a target_entry_amountend condition.","readOnly":true}},"additionalProperties":false,"type":"object","required":["name","end_condition","product_id","product_user_id","user_amount","user_amount_today","current_win_probability","projected_win_probability"],"title":"RaffleUserView","example":{"contest_type":"raffle","country_isos":"ca,us","created_at":"2025-06-12T21:12:58.061205Z","current_amount":4723,"current_participants":12,"current_win_probability":0.0889265297480415,"description":"iPhone winner will be drawn in proportion to entry amount. Contest ends once $800 has been entered.","end_condition":{"target_entry_amount":80000},"entry_rule":{"max_daily_entries_per_user":1000,"max_entry_amount_per_user":10000},"entry_type":"cash","name":"Win an iPhone","prizes":[{"estimated_cash_value":80000,"kind":"physical","name":"iPhone 16"}],"product_id":"1108d053e4fa47c5b0dbdcd03a7981e7","product_user_id":"test-user","projected_win_probability":0.005249999999999977,"starts_at":"2025-06-12T21:12:58.061170Z","status":"active","updated_at":"2025-06-12T21:12:58.061205Z","user_amount":420,"user_amount_today":0,"user_winnings":[],"uuid":"ce3968b8e18a4b96af62007f262ed7f7"}},"RedemptionCurrency":{"type":"string","enum":["USD","CAD","GBP","EUR","INR","AUD","PLN","SEK","SGD","MXN"],"title":"RedemptionCurrency","description":"Supported Currencies for Foreign Redemptions"},"ReportTask":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"product_user_id","description":"The unique identifier for the user, which is set by the Supplier.","examples":["app-user-9329ebd"]},"reasons":{"items":{"$ref":"#/components/schemas/ReportValue"},"type":"array","title":"Reasons","description":"The reason a user reported a task.\n\nAllowed values: \n - __0__ *(REASON_UNKNOWN)*: Used to indicate the user exited the task without giving feedback\n - __1__ *(TECHNICAL_ERROR)*: Task is in the wrong language/country, unanswerable question, won't proceed to next question, loading forever, error message\n - __2__ *(NO_REDIRECT)*: Task ended (completed or failed, and showed the user some dialog indicating the task was over), but failed to redirect\n - __3__ *(PRIVACY_INVASION)*: Asked for full name, home address, identity on another site, cc\n - __4__ *(UNCOMFORTABLE_TOPICS)*: Asked about children, employer, medical issues, drug use, STDs, etc.\n - __5__ *(ASKED_FOR_NOT_ALLOWED_ACTION)*: Asked to install software, signup/login to external site, access webcam, promise to pay using external site, etc.\n - __6__ *(BAD_ON_MOBILE)*: Task doesn't work well on a mobile device\n - __7__ *(DIDNT_LIKE)*: Too long, too boring, confusing, complicated, too many open-ended/free-response questions","examples":[[3,4]]},"notes":{"type":"string","title":"Notes","default":"","examples":["The survey wanted to watch me eat Haejang-guk"]}},"additionalProperties":false,"type":"object","required":["bpuid"],"title":"ReportTask"},"ReportValue":{"type":"integer","enum":[0,1,2,3,4,5,6,7],"title":"ReportValue","description":"The reason a user reported a task."},"Scope":{"type":"string","enum":["global","team","product"],"title":"Scope"},"SessionAdjustedStatus":{"type":"string","enum":["ac","af","pa"],"title":"SessionAdjustedStatus","description":"An adjusted_status is set if a session is adjusted by the marketplace\nafter the original return. A session can be adjusted multiple times.\nThis is the most recent status. If a session was originally a complete,\nwas adjusted to incomplete, then back to complete, the adjusted_status\nwill be None, but the adjusted_timestamp will be set to the most recent\nchange."},"SessionConfig":{"properties":{"max_session_len":{"type":"integer","maximum":5400.0,"minimum":60.0,"title":"Max Session Len","description":"The amount of time (in seconds) that a respondent may spend attempting to get into a survey within a session.If NULL, there is no limit.","default":600},"max_session_hard_retry":{"type":"integer","minimum":0.0,"title":"Max Session Hard Retry","description":"The number of surveys that a respondent may attempt within a session before the session is terminated.","default":5},"min_payout":{"type":"string","title":"Min Payout","description":"The minimum amount the user should be paid for a complete. If \n no payout transformation is defined, the value is based on the BP's payout. \n If a payout transformation is defined, the min_payout is applied on the \n user's payout. Note, this is separate and distinct from the payout \n transformation's min payout. The payout transformation's min_payout does not \n care what the task's actual payout was. This min_payout will prevent\n the user from being show any tasks that would pay below this amount.","default":"0.14","examples":["0.50"]}},"type":"object","title":"SessionConfig","description":"Stores configuration related to the Session, a session being a users\nexperience attempting to do work."},"SessionEnterPayload":{"properties":{"event_type":{"type":"string","const":"session.enter","title":"Event Type","default":"session.enter"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"}},"type":"object","required":["country_iso"],"title":"SessionEnterPayload"},"SessionFinishPayload":{"properties":{"event_type":{"type":"string","const":"session.finish","title":"Event Type","default":"session.finish"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"duration_sec":{"type":"number","exclusiveMinimum":0.0,"title":"Duration Sec"},"status":{"$ref":"#/components/schemas/Status"},"status_code_1":{"anyOf":[{"$ref":"#/components/schemas/StatusCode1"},{"type":"null"}]},"status_code_2":{"anyOf":[{"$ref":"#/components/schemas/SessionStatusCode2"},{"type":"null"}]},"user_payout":{"anyOf":[{"type":"integer","maximum":4000.0,"minimum":0.0},{"type":"null"}],"title":"User Payout"}},"type":"object","required":["country_iso","duration_sec","status"],"title":"SessionFinishPayload"},"SessionStatusCode2":{"type":"integer","enum":[1,2,3,4,5,6,7,8,9,10,11,12,13],"title":"SessionStatusCode2","description":"__Status Detail__\nThis should be set if the Session.status_code_1 is SESSION_XXX_FAIL"},"ShippingCarrier":{"type":"string","enum":["USPS","FedEx","UPS","DHL"],"title":"ShippingCarrier"},"ShippingMethod":{"type":"string","enum":["Standard","Express","Two-Day","Overnight","Same Day"],"title":"ShippingMethod"},"SingleEntryBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]}},"additionalProperties":false,"type":"object","required":["id","uri"],"title":"SingleEntryBucket"},"SingleEntryOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/SingleEntryBucket"},"type":"array","maxItems":1,"title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]},"payout_format":{"type":"string","title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]}},"additionalProperties":false,"type":"object","required":["id","availability_count","payout_format"],"title":"SingleEntryOfferWall","description":"Only returns a single bucket with the top scoring tasks.\n\nOfferwall code: `5fl8bpv5`"},"SingleEntryOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/SingleEntryOfferWall"}},"type":"object","required":["info","offerwall"],"title":"SingleEntryOfferWallResponse"},"SoftPairBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way. If the eligibility is conditional or ineligible, the uri will be null.","examples":[null]},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"eligibility":{"type":"string","enum":["conditional","unconditional","ineligible"],"title":"Eligibility","examples":["conditional"]},"missing_questions":{"items":{"type":"string"},"type":"array","title":"Missing Questions","examples":[["fb20fd4773304500b39c4f6de0012a5a"]]},"loi":{"type":"integer","title":"Loi","description":"this is the max loi of the contents","examples":[612]},"payout":{"type":"integer","title":"Payout","description":"this is the min payout of the contents","examples":[123]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","eligibility","loi","payout"],"title":"SoftPairBucket"},"SoftPairOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/SoftPairBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]},"question_info":{"additionalProperties":{"$ref":"#/components/schemas/UpkQuestion"},"type":"object","title":"Question Info","examples":[]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"SoftPairOfferwall","description":"This offerwall contains tasks for which the user has a conditional\neligibility. The questions that a user must answer to determine the\neligibility are included within each bucket. Additionally, the question\ndefinitions are included for convenience.\n\nOfferwall code: `37d1da64`"},"SoftPairOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/SoftPairOfferwall"}},"type":"object","required":["info","offerwall"],"title":"SoftPairOfferwallResponse"},"Source":{"type":"string","enum":["g","c","a","d","et","f","i","l","m","n","o","e","r","pr","p","rd","h","s","t","u","w"],"title":"Source"},"SourceConfig":{"properties":{"name":{"$ref":"#/components/schemas/Source"},"active":{"type":"boolean","title":"Active","default":true},"banned_countries":{"items":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},"type":"array","title":"Banned Countries"},"allow_mobile_ip":{"type":"boolean","title":"Allow Mobile Ip","default":true},"allow_pii_only_buyers":{"type":"boolean","title":"Allow Pii Only Buyers","description":"Allow Tasks from Buyers that want traffic that comes from Suppliers that can identify their users. Only supported on Pure Spectrum.","default":false},"allow_unhashed_buyers":{"type":"boolean","title":"Allow Unhashed Buyers","description":"Return Tasks from Buyers that don't have URL hashing enabled. Only supported on Pure Spectrum.","default":false},"withhold_profiling":{"type":"boolean","title":"Withhold Profiling","description":"For some Products, we may have privacy agreements prohibiting us from sharing information with the inventorySource. If True, don't add MRPQ (Market Research ProfilingQuestion) onto the entry link.","default":false},"pass_unconditional_eligible_unknowns":{"type":"boolean","title":"Pass Unconditional Eligible Unknowns","description":"Not used at the moment","default":true}},"type":"object","required":["name"],"title":"SourceConfig","description":"This could also be named \"BP:Marketplace Config\", as it describes the config\nfor a BP on a single marketplace."},"SourcesConfig":{"properties":{"user_defined":{"items":{"$ref":"#/components/schemas/SourceConfig"},"type":"array","title":"User Defined"}},"type":"object","title":"SourcesConfig","description":"Describes the marketplaces or sources that a BP can access and their respective configs,\naka 'BP:Marketplace Configs'"},"StarwallOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]},"payout_format":{"type":"string","title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]}},"additionalProperties":false,"type":"object","required":["id","availability_count","payout_format"],"title":"StarwallOfferWall","description":"An offerwall with buckets that are clustered by setting as seeds the\nhighest scoring surveys for each bin, then the rest are distributed\naccording to their Euclidean distance using the bucket's features.\n\nOfferwall code: `b59a2d2b`"},"StarwallOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/StarwallOfferWall"}},"type":"object","required":["info","offerwall"],"title":"StarwallOfferWallResponse"},"StarwallPlusBlockOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"StarwallPlusBlockOfferWall","description":"Same as the StarwallOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.\n\nOfferwall code: `7fa1b3f4`"},"StarwallPlusBlockOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/StarwallPlusBlockOfferWall"}},"type":"object","required":["info","offerwall"],"title":"StarwallPlusBlockOfferWallResponse"},"StarwallPlusBlockRecontactOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusRecontactBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"StarwallPlusBlockRecontactOfferWall","description":"Same as the StarwallOfferWall, but the buckets include contents, no\nbuckets are returned if the user is blocked, and each bucket includes\na recontact key.\n\nOfferwall code: `630db2a4`"},"StarwallPlusBlockRecontactOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/StarwallPlusBlockRecontactOfferWall"}},"type":"object","required":["info","offerwall"],"title":"StarwallPlusBlockRecontactOfferWallResponse"},"StarwallPlusOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"StarwallPlusOfferWall","description":"Same as the StarwallOfferWall, but the buckets include contents.\n\nOfferwall code: `5481f322`"},"StarwallPlusOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/StarwallPlusOfferWall"}},"type":"object","required":["info","offerwall"],"title":"StarwallPlusOfferWallResponse"},"StatisticalSummaryStat":{"properties":{"facet":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"number"}]},"propertyNames":{"enum":["country_iso","day","month"]},"type":"object","title":"Facet","description":"The grouping criteria","examples":[{"country_iso":"us"}]},"value":{"$ref":"#/components/schemas/StatisticalSummaryValue","description":"Statistical Summary for the given metric and facet"}},"type":"object","required":["facet","value"],"title":"StatisticalSummaryStat"},"StatisticalSummaryValue":{"properties":{"min":{"type":"number","title":"Min"},"max":{"type":"number","title":"Max"},"mean":{"type":"number","title":"Mean"},"q1":{"type":"number","title":"Q1"},"q2":{"type":"number","title":"Q2","description":"equal to the median"},"q3":{"type":"number","title":"Q3"},"lower_whisker":{"type":"number","title":"Lower Whisker","readOnly":true},"upper_whisker":{"type":"number","title":"Upper Whisker","readOnly":true}},"type":"object","required":["min","max","mean","q1","q2","q3","lower_whisker","upper_whisker"],"title":"StatisticalSummaryValue"},"StatsMessage":{"properties":{"kind":{"type":"string","const":"stats","title":"Kind","default":"stats"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"country_iso":{"anyOf":[{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},{"type":"null"}],"title":"Country Iso"},"data":{"$ref":"#/components/schemas/StatsSnapshot"}},"type":"object","required":["data"],"title":"StatsMessage"},"StatsSnapshot":{"properties":{"live_task_count":{"$ref":"#/components/schemas/AggregateBySource"},"task_created_count_last_1h":{"$ref":"#/components/schemas/AggregateBySource"},"task_created_count_last_24h":{"$ref":"#/components/schemas/AggregateBySource"},"live_tasks_max_payout":{"$ref":"#/components/schemas/MaxGaugeBySource","description":"In integer USDCents"},"country_iso":{"anyOf":[{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},{"type":"null"}],"title":"Country Iso"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"active_users_last_1h":{"type":"integer","minimum":0.0,"title":"Active Users Last 1H","description":"Count of users (in this product_id) that were active in the past 60 minutes.\n Behaviors that trigger active:\n - Request an offerwall\n - Enter an offerwall bucket\n - Request profiling questions\n - Submit profiling answers\n - Update user profile\n ","default":0},"active_users_last_24h":{"type":"integer","minimum":0.0,"title":"Active Users Last 24H","description":"Count of users (in this product_id) that were active in the past 24 hours.","default":0},"in_progress_users":{"type":"integer","minimum":0.0,"title":"In Progress Users","description":"Count of users that are currently doing work at this moment"},"signups_last_24h":{"type":"integer","minimum":0.0,"title":"Signups Last 24H","description":"Count of users created"},"session_enters_last_1h":{"type":"integer","minimum":0.0,"title":"Session Enters Last 1H"},"session_enters_last_24h":{"type":"integer","minimum":0.0,"title":"Session Enters Last 24H"},"session_fails_last_1h":{"type":"integer","minimum":0.0,"title":"Session Fails Last 1H"},"session_fails_last_24h":{"type":"integer","minimum":0.0,"title":"Session Fails Last 24H"},"session_completes_last_1h":{"type":"integer","minimum":0.0,"title":"Session Completes Last 1H"},"session_completes_last_24h":{"type":"integer","minimum":0.0,"title":"Session Completes Last 24H"},"sum_payouts_last_1h":{"type":"integer","minimum":0.0,"title":"Sum Payouts Last 1H","description":"In integer USDCents"},"sum_payouts_last_24h":{"type":"integer","minimum":0.0,"title":"Sum Payouts Last 24H","description":"In integer USDCents"},"session_avg_payout_last_24h":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Session Avg Payout Last 24H","description":"Average (actual) payout of all tasks completed in the past 24 hrs"},"session_avg_user_payout_last_24h":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Session Avg User Payout Last 24H","description":"Average (actual) user payout of all tasks completed in the past 24 hrs"},"session_fail_avg_loi_last_24h":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Session Fail Avg Loi Last 24H","description":"Average LOI of all tasks terminated in the past 24 hrs (excludes abandons)"},"session_complete_avg_loi_last_24h":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Session Complete Avg Loi Last 24H","description":"Average LOI of all tasks completed in the past 24 hrs"}},"type":"object","required":["in_progress_users","signups_last_24h","session_enters_last_1h","session_enters_last_24h","session_fails_last_1h","session_fails_last_24h","session_completes_last_1h","session_completes_last_24h","sum_payouts_last_1h","sum_payouts_last_24h","session_avg_payout_last_24h","session_avg_user_payout_last_24h","session_fail_avg_loi_last_24h","session_complete_avg_loi_last_24h"],"title":"StatsSnapshot"},"Status":{"type":"string","enum":["c","f","a","t"],"title":"Status","description":"The outcome of a session or wall event. If the session is still in progress, the status will be NULL."},"StatusCode1":{"type":"integer","enum":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"title":"StatusCode1","description":"__High level status code for outcome of the session.__\nThis should only be NULL if the Status is ABANDON or TIMEOUT"},"StatusInfoResponseFail":{"properties":{"info":{"$ref":"#/components/schemas/StatusSuccessFail"},"msg":{"type":"string","title":"Msg","description":"An optional message, if success is False","examples":["An error has occurred"]}},"type":"object","required":["info","msg"],"title":"StatusInfoResponseFail"},"StatusResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]}},"type":"object","required":["status"],"title":"StatusResponse"},"StatusResponseFailure":{"properties":{"status":{"type":"string","const":"failure","title":"Status","description":"The status of the API response.","examples":["failure"]},"msg":{"type":"string","title":"Msg","description":"An optional message, if the status is failure.","examples":["An error has occurred"]}},"type":"object","required":["status","msg"],"title":"StatusResponseFailure"},"StatusSuccessFail":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the API response is successful.","default":false}},"type":"object","title":"StatusSuccessFail"},"StreakFulfillment":{"type":"string","enum":["active","complete"],"title":"StreakFulfillment","description":"What has to happen for a user to fulfill a period for a streak"},"StreakPeriod":{"type":"string","enum":["day","week","month"],"title":"StreakPeriod"},"StreakState":{"type":"string","enum":["active","at_risk","broken"],"title":"StreakState"},"SubscribeMessage":{"properties":{"kind":{"type":"string","const":"subscribe","title":"Kind","default":"subscribe"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]}},"type":"object","required":["product_id"],"title":"SubscribeMessage"},"SupplierTag":{"type":"string","enum":["mobile","js-offerwall","double-opt-in","single-sign-on","phone-number-verified","test-a","test-b"],"title":"SupplierTag","description":"Available tags which can be used to annotate supplier traffic\n\nNote: should not include commas!"},"SupplyConfig":{"properties":{"policies":{"items":{"$ref":"#/components/schemas/SupplyPolicy"},"type":"array","title":"Policies"}},"type":"object","title":"SupplyConfig","description":"Describes the set of policies for how GRL can interact with marketplaces.\nThis is only used on the special \"global product\"."},"SupplyPolicy":{"properties":{"name":{"$ref":"#/components/schemas/Source"},"active":{"type":"boolean","title":"Active","default":true},"banned_countries":{"items":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},"type":"array","title":"Banned Countries"},"allow_mobile_ip":{"type":"boolean","title":"Allow Mobile Ip","default":true},"allow_pii_only_buyers":{"type":"boolean","title":"Allow Pii Only Buyers","description":"Allow Tasks from Buyers that want traffic that comes from Suppliers that can identify their users. Only supported on Pure Spectrum.","default":false},"allow_unhashed_buyers":{"type":"boolean","title":"Allow Unhashed Buyers","description":"Return Tasks from Buyers that don't have URL hashing enabled. Only supported on Pure Spectrum.","default":false},"withhold_profiling":{"type":"boolean","title":"Withhold Profiling","description":"For some Products, we may have privacy agreements prohibiting us from sharing information with the inventorySource. If True, don't add MRPQ (Market Research ProfilingQuestion) onto the entry link.","default":false},"pass_unconditional_eligible_unknowns":{"type":"boolean","title":"Pass Unconditional Eligible Unknowns","description":"Not used at the moment","default":true},"address":{"items":{"type":"string"},"type":"array","title":"Address","description":"address for the grpc GetOpps call"},"allow_vpn":{"type":"boolean","title":"Allow Vpn","default":false},"distribute_harmonizer_active":{"type":"boolean","title":"Distribute Harmonizer Active","default":true},"supplier_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplier Id","description":"For some inventory Sources, we may partition traffic using different supplier accounts instead"},"team_ids":{"anyOf":[{"items":{"type":"string","maxLength":32,"minLength":32},"type":"array"},{"type":"null"}],"title":"Team Ids"},"product_ids":{"anyOf":[{"items":{"type":"string","maxLength":32,"minLength":32},"type":"array"},{"type":"null"}],"title":"Product Ids"},"integration_mode":{"$ref":"#/components/schemas/IntegrationMode","default":"platform"},"scope":{"$ref":"#/components/schemas/Scope","description":"There must be only 1 GLOBAL config per Source. We can have more than one TEAM/PRODUCT config per Source.","readOnly":true}},"type":"object","required":["name","address","scope"],"title":"SupplyPolicy","description":"One policy describing how GRL can interact with a marketplaces in a certain way.\n This is only used on the special \"global product\", and then internally\n in grpc logic."},"SurveyEligibilityCriterion":{"properties":{"question_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Question Id","examples":["71a367fb71b243dc89f0012e0ec91749"]},"property_code":{"anyOf":[{"type":"string","maxLength":64,"minLength":3,"pattern":"^[a-z]{1,2}\\:.*"},{"type":"null"}],"title":"Property Code","examples":["c:73629"]},"question_text":{"type":"string","title":"Question Text","examples":["What company administers the retirement plan for your current employer?"]},"qualifying_answer":{"items":{"type":"string"},"type":"array","title":"Qualifying Answer","description":"User answer(s) that satisfied at least one eligibility rule","examples":["121"]},"qualifying_answer_label":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Qualifying Answer Label","examples":["Fidelity Investments"]},"explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation","description":"Human-readable text explaining how a user's answer to this question affects eligibility","examples":["The company that administers your employer's retirement plan is **Fidelity Investments**."]},"rank":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Rank","description":"Lower values are shown more prominently in the UI"}},"type":"object","required":["question_id","property_code","question_text","qualifying_answer","qualifying_answer_label"],"title":"SurveyEligibilityCriterion","description":"Explanatory record of which question answers contributed\n to a user's eligibility for a survey.\nThis is INSUFFICIENT for determining eligibility to a task\n as it IGNORES logical operators, dependencies between criteria,\n and other requirements. It is only intended for the UI."},"TangoCashoutMethodData":{"properties":{"type":{"type":"string","const":"TANGO","title":"Type","default":"TANGO"},"utid":{"type":"string","title":"Utid","description":"tango utid"},"countries":{"items":{"type":"string"},"type":"array","title":"Countries"},"value_type":{"type":"string","enum":["variable","fixed"],"title":"Value Type"},"disclaimer":{"type":"string","title":"Disclaimer","default":""},"terms":{"type":"string","title":"Terms","default":""}},"type":"object","required":["utid","countries","value_type"],"title":"TangoCashoutMethodData"},"TaskEnterPayload":{"properties":{"event_type":{"type":"string","const":"task.enter","title":"Event Type","default":"task.enter"},"source":{"$ref":"#/components/schemas/Source"},"survey_id":{"type":"string","maxLength":32,"minLength":1,"title":"Survey Id","examples":["127492892"]},"quota_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Quota Id","description":"The marketplace's internal quota id"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"}},"type":"object","required":["source","survey_id","country_iso"],"title":"TaskEnterPayload"},"TaskFinishPayload":{"properties":{"event_type":{"type":"string","const":"task.finish","title":"Event Type","default":"task.finish"},"source":{"$ref":"#/components/schemas/Source"},"survey_id":{"type":"string","maxLength":32,"minLength":1,"title":"Survey Id","examples":["127492892"]},"quota_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Quota Id","description":"The marketplace's internal quota id"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"duration_sec":{"type":"number","exclusiveMinimum":0.0,"title":"Duration Sec"},"status":{"$ref":"#/components/schemas/Status"},"status_code_1":{"anyOf":[{"$ref":"#/components/schemas/StatusCode1"},{"type":"null"}]},"status_code_2":{"anyOf":[{"$ref":"#/components/schemas/WallStatusCode2"},{"type":"null"}]},"cpi":{"anyOf":[{"type":"integer","maximum":4000.0,"minimum":0.0},{"type":"null"}],"title":"Cpi"}},"type":"object","required":["source","survey_id","country_iso","duration_sec","status"],"title":"TaskFinishPayload"},"TaskStatusResponse":{"properties":{"tsid":{"type":"string","maxLength":32,"minLength":32,"title":"Tsid","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"The BP ID of the associated respondent","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"product_user_id":{"type":"string","maxLength":128,"minLength":3,"title":"Product User Id","description":"A unique identifier for each user, which is set by the Supplier","examples":["app-user-9329ebd"]},"started":{"type":"string","format":"date-time","title":"Started","description":"When the session was started"},"finished":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished","description":"When the session was finished"},"status":{"type":"integer","description":"The outcome of a session.\n - 0 - UNKNOWN\n - 1 - ENTER (the user has not yet returned)\n - 2 - INCOMPLETE (the user failed)\n - 3 - COMPLETE (the user completed the task)","examples":[3]},"payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"Payout","description":"The amount paid to the supplier, in integer USD cents","examples":[500]},"user_payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"User Payout","description":"If a payout transformation is configured on this account, this is the amount the user should earn, in integer USD cents","examples":[337]},"payout_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]},"user_payout_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Payout String","description":"If a payout transformation is configured on this account, this is the amount to display to the user","examples":["3370 Points"]},"kwargs":{"additionalProperties":{"type":"string"},"type":"object","title":"Kwargs","description":"Any extra url params used in the offerwall request will be passed back here"},"status_code_1":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"__High level status code for outcome of the session.__\nThis should only be NULL if the Status is ABANDON or TIMEOUT\n\nAllowed values: \n - __BUYER_FAIL__: User terminated in buyer survey\n - __BUYER_QUALITY_FAIL__: User terminated in buyer survey for quality reasons\n - __PS_FAIL__: User failed in marketplace's prescreener\n - __PS_QUALITY__: User rejected by marketplace for quality reasons\n - __PS_BLOCKED__: User is explicitly blocked by the marketplace. Note: on some marketplaces, users can have multiple PS_QUALITY terminations and still complete surveys.\n - __PS_OVERQUOTA__: User rejected by marketplace for over quota\n - __PS_DUPLICATE__: User rejected by marketplace for duplicate\n - __GRS_FAIL__: The user failed within the GRS Platform\n - __GRS_QUALITY_FAIL__: The user failed within the GRS Platform for quality reasons\n - __GRS_ABANDON__: The user abandoned/timed out within the GRS Platform\n - __PS_ABANDON__: The user abandoned/timed out within the marketplace's pre-screen system. Note: On most marketplaces, we have no way of distinguishing between this and BUYER_ABANDON. BUYER_ABANDON is used as the default, unless we know it is PS_ABANDON.\n - __BUYER_ABANDON__: The user abandoned/timed out within the client survey\n - __UNKNOWN__: The status code is not documented\n - __COMPLETE__: The user completed the task successfully\n - __MARKETPLACE_FAIL__: Something was wrong upon the user redirecting from the marketplace, e.g. no postback received, or url hashing failures.\n - __SESSION_START_FAIL__: User failed before being sent into a marketplace\n - __SESSION_CONTINUE_FAIL__: User failed between attempts\n - __SESSION_START_QUALITY_FAIL__: User failed before being sent into a marketplace for \"security\" reasons\n - __SESSION_CONTINUE_QUALITY_FAIL__: User failed between attempts for \"security\" reasons","examples":["COMPLETE"]},"status_code_2":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"__Status Detail__\nThis should be set if the Session.status_code_1 is SESSION_XXX_FAIL\n\nAllowed values: \n - __ENTRY_URL_MODIFICATION__: Unable to parse either the bucket_id, request_id, or nudge_id from the url\n - __UNRECOGNIZED_IP__: The client's IP failed maxmind lookup, or we failed to store it for some reason\n - __USER_IS_ANONYMOUS__: User is using an anonymous IP\n - __USER_IS_BLOCKED__: User is blocked\n - __USER_IS_RATE_LIMITED__: User is rate limited\n - __UNRECOGNIZED_DEVICE__: The client's useragent was not categorized as desktop, mobile, or tablet\n - __OFFERWALL_EXPIRED__: The user clicked after 5 min\n - __INTERNAL_ERROR__: Something unexpected happened\n - __OFFERWALL_COUNTRY_MISMATCH__: The user requested the offerwall for a different country than their IP address indicates\n - __INVALID_BUCKET_ID__: The bucket id indicated in the url does not exist. This is likely due to the user clicking on a bucket for an offerwall that has already been refreshed.\n - __NO_TASKS_AVAILABLE__: Not necessarily the user's fault. We thought we had surveys, but due to for e.g. the user entering on a different device than we thought, there really are none. If we get a lot of these, then that might indicate something is wrong.\n - __ATTEMPT_IS_SUSPICIOUS__: The entrance attempt was flagged by GRLIQ as suspicious\n - __GRLIQ_MISSING__: No GRLIQ forensics post was received","examples":[null]},"adjusted_status":{"anyOf":[{"$ref":"#/components/schemas/SessionAdjustedStatus"},{"type":"null"}],"description":"An adjusted_status is set if a session is adjusted by the marketplace\nafter the original return. A session can be adjusted multiple times.\nThis is the most recent status. If a session was originally a complete,\nwas adjusted to incomplete, then back to complete, the adjusted_status\nwill be None, but the adjusted_timestamp will be set to the most recent\nchange.\n\nAllowed values: \n - __ac__ *(ADJUSTED_TO_COMPLETE)*: Task was reconciled to complete\n - __af__ *(ADJUSTED_TO_FAIL)*: Task was reconciled to incomplete\n - __pa__ *(PAYOUT_ADJUSTMENT)*: The payout was changed. This applies to Sessions ONLY.","examples":[null]},"adjusted_timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Adjusted Timestamp","description":"When the adjusted status was last set.","examples":[null]},"adjusted_payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"Adjusted Payout","description":"The new payout after adjustment.","examples":[null]},"adjusted_user_payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"Adjusted User Payout","description":"The new user_payout after adjustment.","examples":[null]},"adjusted_user_payout_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Adjusted User Payout String","description":"The new user_payout_string after adjustment.","examples":[null]},"wall_events":{"anyOf":[{"items":{"$ref":"#/components/schemas/WallOut"},"type":"array"},{"type":"null"}],"title":"Wall Events"},"currency":{"type":"string","const":"USD","title":"Currency","default":"USD"},"final_status":{"type":"integer","title":"Final Status","description":"This is deprecated","default":0},"bpuid":{"type":"string","title":"Bpuid","readOnly":true}},"type":"object","required":["tsid","product_id","product_user_id","started","bpuid"],"title":"TaskStatusResponse","description":"The status of a session"},"TasksStatusResponse":{"properties":{"page":{"type":"integer","minimum":1.0,"title":"Page","description":"Page number","default":1},"size":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Size","description":"Page size","default":50},"total":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Total","description":"Total number of results"},"tasks_status":{"items":{"$ref":"#/components/schemas/TaskStatusResponse"},"type":"array","title":"Tasks Status"},"pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pages","description":"Total number of pages","readOnly":true}},"type":"object","required":["pages"],"title":"TasksStatusResponse"},"TopNBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"x":{"type":"integer","minimum":0.0,"title":"X","description":"For UI. Provides a dimensionality position for the bucket on the x-axis.","default":0,"examples":[0,1,2]},"y":{"type":"integer","minimum":0.0,"title":"Y","description":"For UI. Provides a dimensionality position for the bucket on the y-axis.","default":0,"examples":[0,1,2]},"name":{"type":"string","title":"Name","description":"Currently unused. Will always return empty string","default":""},"description":{"type":"string","title":"Description","description":"Currently unused. Will always return empty string","default":""},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"duration":{"$ref":"#/components/schemas/DurationSummary"},"payout":{"$ref":"#/components/schemas/PayoutSummary"},"quality_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Quality Score","description":"A proprietary score to determine the overall quality of the tasks that are within the bucket. Higher is better.","examples":[0.29223]}},"additionalProperties":false,"type":"object","required":["id","uri","duration","payout","quality_score"],"title":"TopNBucket"},"TopNOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]},"payout_format":{"type":"string","title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]}},"additionalProperties":false,"type":"object","required":["id","availability_count","payout_format"],"title":"TopNOfferWall","description":"An offerwall with buckets that are clustered by the `split_by` argument\nusing KMeans clustering.\n\nOfferwall code: `45b7228a7`"},"TopNOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/TopNOfferWall"}},"type":"object","required":["info","offerwall"],"title":"TopNOfferWallResponse"},"TopNPlusBlockOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"TopNPlusBlockOfferWall","description":"Same as the TopNOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.\n\nOfferwall code: `d48cce47`"},"TopNPlusBlockOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/TopNPlusBlockOfferWall"}},"type":"object","required":["info","offerwall"],"title":"TopNPlusBlockOfferWallResponse"},"TopNPlusBlockRecontactOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusRecontactBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"TopNPlusBlockRecontactOfferWall","description":"Same as the TopNOfferWall, but the buckets include contents, no buckets\nare returned if the user is blocked, and each bucket includes a\n`is_recontact` key.\n\nOfferwall code: `1e5f0af8`"},"TopNPlusBlockRecontactOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/TopNPlusBlockRecontactOfferWall"}},"type":"object","required":["info","offerwall"],"title":"TopNPlusBlockRecontactOfferWallResponse"},"TopNPlusBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"x":{"type":"integer","minimum":0.0,"title":"X","description":"For UI. Provides a dimensionality position for the bucket on the x-axis.","default":0,"examples":[0,1,2]},"y":{"type":"integer","minimum":0.0,"title":"Y","description":"For UI. Provides a dimensionality position for the bucket on the y-axis.","default":0,"examples":[0,1,2]},"name":{"type":"string","title":"Name","description":"Currently unused. Will always return empty string","default":""},"description":{"type":"string","title":"Description","description":"Currently unused. Will always return empty string","default":""},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"duration":{"$ref":"#/components/schemas/DurationSummary"},"payout":{"$ref":"#/components/schemas/PayoutSummary"},"quality_score":{"type":"number","title":"Quality Score"},"currency":{"type":"string","title":"Currency","description":"This will always be 'USD'","default":"USD","examples":["USD"]},"eligibility_criteria":{"items":{"$ref":"#/components/schemas/SurveyEligibilityCriterion"},"type":"array","title":"Eligibility Criteria","description":"The reasons the user is eligible for tasks in this bucket"},"eligibility_explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Eligibility Explanation","description":"Human-readable text explaining a user's eligibility for tasks in this bucket","examples":["You are a **47-year-old** **white** **male** with a *college degree*, who's employer's retirement plan is **Fidelity Investments**."]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","duration","payout","quality_score"],"title":"TopNPlusBucket"},"TopNPlusOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"TopNPlusOfferWall","description":"Same as the TopNOfferWall, but the buckets include contents.\n\nOfferwall code: `b145b803`"},"TopNPlusOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/TopNPlusOfferWall"}},"type":"object","required":["info","offerwall"],"title":"TopNPlusOfferWallResponse"},"TopNPlusRecontactBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"x":{"type":"integer","minimum":0.0,"title":"X","description":"For UI. Provides a dimensionality position for the bucket on the x-axis.","default":0,"examples":[0,1,2]},"y":{"type":"integer","minimum":0.0,"title":"Y","description":"For UI. Provides a dimensionality position for the bucket on the y-axis.","default":0,"examples":[0,1,2]},"name":{"type":"string","title":"Name","description":"Currently unused. Will always return empty string","default":""},"description":{"type":"string","title":"Description","description":"Currently unused. Will always return empty string","default":""},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"duration":{"$ref":"#/components/schemas/DurationSummary"},"payout":{"$ref":"#/components/schemas/PayoutSummary"},"quality_score":{"type":"number","title":"Quality Score"},"is_recontact":{"type":"boolean","title":"Is Recontact"},"currency":{"type":"string","title":"Currency","description":"This will always be 'USD'","default":"USD","examples":["USD"]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","duration","payout","quality_score","is_recontact"],"title":"TopNPlusRecontactBucket"},"UPKImportance":{"properties":{"task_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Task Count","description":"The number of live Tasks that use this UPK Question","examples":[47]},"task_score":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Task Score","description":"GRL's internal ranked score for the UPK Question","examples":[0.11175522477414712]},"marketplace_task_count":{"anyOf":[{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object"},{"type":"null"}],"title":"Marketplace Task Count","description":"The number of live Tasks that use this UPK Question per marketplace","examples":[{"d":23,"s":24}]}},"type":"object","title":"UPKImportance"},"USDeliveryAddress":{"properties":{"name_or_attn":{"type":"string","maxLength":50,"minLength":1,"title":"Name Or Attn"},"company":{"anyOf":[{"type":"string","maxLength":50,"minLength":1},{"type":"null"}],"title":"Company"},"phone_number":{"anyOf":[{"type":"string","maxLength":10,"minLength":10,"pattern":"^[0-9]+$"},{"type":"null"}],"title":"Phone Number"},"address":{"type":"string","maxLength":100,"minLength":1,"title":"Address"},"city":{"type":"string","maxLength":100,"minLength":1,"title":"City"},"state":{"type":"string","maxLength":2,"minLength":1,"title":"State"},"postal_code":{"type":"string","maxLength":10,"minLength":1,"title":"Postal Code"},"country":{"type":"string","title":"Country","default":"us"}},"type":"object","required":["name_or_attn","address","city","state","postal_code"],"title":"USDeliveryAddress"},"UpkItem":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","examples":["497b1fedec464151b063cd5367643ffa"]},"label":{"type":"string","maxLength":255,"title":"Label","examples":["high_school_completion"]},"description":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Description","examples":["Completed high school"]}},"type":"object","required":["id","label"],"title":"UpkItem"},"UpkProperty":{"properties":{"property_id":{"type":"string","maxLength":32,"minLength":32,"title":"Property Id","examples":["2af5240ecd7d4a909a6caf5824bf4632"]},"property_label":{"type":"string","maxLength":255,"title":"Property Label","examples":["educational_attainment"]},"prop_type":{"$ref":"#/components/schemas/PropertyType","description":"\nAllowed values: \n - __i__ *(UPK_ITEM)*: UserProfileKnowledge Item\n - __n__ *(UPK_NUMERICAL)*: UserProfileKnowledge Numerical\n - __x__ *(UPK_TEXT)*: UserProfileKnowledge Text","default":"i"},"cardinality":{"$ref":"#/components/schemas/Cardinality","description":"\nAllowed values: \n - __*__ *(ZERO_OR_MORE)*: Zero or More\n - __?__ *(ZERO_OR_ONE)*: Zero or One","default":"?"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"gold_standard":{"type":"boolean","title":"Gold Standard","description":"A Gold-Standard question has been enumerated for all possible values (per country) as best as possible by GRL,allowing it to be mapped across inventory sources. A property not marked as Gold-Standard may have: 1) marketplace qid associations & 2) category associations, but doesn't have a defined 'range' (list of allowed itemsin a multiple choice question). This is used for exposing a user's profiling data & forthe Nudge API.","default":false},"allowed_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/UpkItem"},"type":"array"},{"type":"null"}],"title":"Allowed Items"},"categories":{"items":{"$ref":"#/components/schemas/Category"},"type":"array","title":"Categories"}},"type":"object","required":["property_id","property_label","country_iso"],"title":"UpkProperty","description":"This used to be called \"QuestionInfo\", which is a bad name,\n as this describes a UPK Property, like \"educational_attainment\",\n not the question that asks for your education."},"UpkQuestion":{"properties":{"question_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Question Id"},"ext_question_id":{"anyOf":[{"type":"string","pattern":"^[a-z]{1,2}\\:.*"},{"type":"null"}],"title":"Ext Question Id","description":"what marketplace question this question links to"},"question_type":{"$ref":"#/components/schemas/UpkQuestionType"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"language_iso":{"type":"string","maxLength":3,"minLength":3,"pattern":"^[a-z]{3}$","title":"Language Iso"},"question_text":{"type":"string","minLength":1,"title":"Question Text","description":"The text shown to respondents"},"choices":{"anyOf":[{"items":{"$ref":"#/components/schemas/UpkQuestionChoice"},"type":"array"},{"type":"null"}],"title":"Choices"},"selector":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionSelectorMC"},{"$ref":"#/components/schemas/UpkQuestionSelectorTE"},{"$ref":"#/components/schemas/UpkQuestionSelectorSLIDER"},{"$ref":"#/components/schemas/UpkQuestionSelectorHIDDEN"}],"title":"Selector"},"configuration":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UpkQuestionConfigurationMC"},{"$ref":"#/components/schemas/UpkQuestionConfigurationTE"},{"$ref":"#/components/schemas/UpkQuestionConfigurationSLIDER"}],"discriminator":{"propertyName":"type","mapping":{"MC":"#/components/schemas/UpkQuestionConfigurationMC","SLIDER":"#/components/schemas/UpkQuestionConfigurationSLIDER","TE":"#/components/schemas/UpkQuestionConfigurationTE"}}},{"type":"null"}],"title":"Configuration"},"validation":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionValidation"},{"type":"null"}]},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]},"categories":{"items":{"$ref":"#/components/schemas/Category"},"type":"array","title":"Categories","description":"Categories associated with this question"},"explanation_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Template","description":"Human-readable template for explaining how a user's answer to this question affects eligibility","examples":["The company that administers your employer's retirement plan is {answer}."]},"explanation_fragment_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Fragment Template","description":"A very short, natural-language explanation fragment that can be combined with others into a single sentence","examples":["whose employer's retirement plan is {answer}"]}},"type":"object","required":["question_type","country_iso","language_iso","question_text"],"title":"UpkQuestion","example":{"categories":[{"adwords_vertical_id":"396","label":"Politics","parent_uuid":"f66dddba61424ce5be2a38731450a0e1","path":"/News/Politics","uuid":"87b6d819f3ca4815bf1f135b1e829cc6"}],"choices":[{"choice_id":"1","choice_text":"Yes","exclusive":false,"order":0},{"choice_id":"2","choice_text":"No","exclusive":false,"order":1}],"country_iso":"us","importance":{"marketplace_task_count":{"d":9,"s":20,"w":20},"task_count":49,"task_score":3.3401743283265684},"language_iso":"eng","marketplace_task_count":{"d":9,"s":20,"w":20},"question_id":"fb20fd4773304500b39c4f6de0012a5a","question_text":"Are you registered to vote at your present address, or not?","question_type":"MC","selector":"SA","task_count":49,"task_score":3.3401743283265684}},"UpkQuestionChoice":{"properties":{"choice_id":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[\\w\\s\\.\\-]+$","title":"Choice Id","description":"The unique identifier for a response to a qualification"},"choice_text":{"type":"string","minLength":1,"title":"Choice Text","description":"The response text shown to respondents"},"order":{"type":"integer","minimum":0.0,"title":"Order"},"group":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group"},"exclusive":{"type":"boolean","title":"Exclusive","description":"If answer is exclusive, it can be the only option selected","default":false},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]}},"type":"object","required":["choice_id","choice_text","order"],"title":"UpkQuestionChoice"},"UpkQuestionChoiceOut":{"properties":{"choice_id":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[\\w\\s\\.\\-]+$","title":"Choice Id","description":"The unique identifier for a response to a qualification"},"choice_text":{"type":"string","minLength":1,"title":"Choice Text","description":"The response text shown to respondents"},"order":{"type":"integer","minimum":0.0,"title":"Order"},"group":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group"},"exclusive":{"type":"boolean","title":"Exclusive","description":"If answer is exclusive, it can be the only option selected","default":false},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]}},"type":"object","required":["choice_id","choice_text","order"],"title":"UpkQuestionChoiceOut"},"UpkQuestionConfigurationMC":{"properties":{"max_select":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Select"}},"additionalProperties":false,"type":"object","title":"UpkQuestionConfigurationMC"},"UpkQuestionConfigurationSLIDER":{"properties":{"slider_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Min"},"slider_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Max"},"slider_start":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Start"},"slider_step":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Step"}},"type":"object","title":"UpkQuestionConfigurationSLIDER"},"UpkQuestionConfigurationTE":{"properties":{"max_length":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Length","description":"Maximum str length of any input. Meant as an easy, nonregex based check."},"min_length":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Min Length","description":"Minimum str length of any input. Meant as an easy, nonregex based check."}},"additionalProperties":false,"type":"object","title":"UpkQuestionConfigurationTE"},"UpkQuestionOut":{"properties":{"question_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Question Id"},"ext_question_id":{"anyOf":[{"type":"string","pattern":"^[a-z]{1,2}\\:.*"},{"type":"null"}],"title":"Ext Question Id","description":"what marketplace question this question links to"},"question_type":{"$ref":"#/components/schemas/UpkQuestionType"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"language_iso":{"type":"string","maxLength":3,"minLength":3,"pattern":"^[a-z]{3}$","title":"Language Iso"},"question_text":{"type":"string","minLength":1,"title":"Question Text","description":"The text shown to respondents"},"choices":{"anyOf":[{"items":{"$ref":"#/components/schemas/UpkQuestionChoiceOut"},"type":"array"},{"type":"null"}],"title":"Choices"},"selector":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionSelectorMC"},{"$ref":"#/components/schemas/UpkQuestionSelectorTE"},{"$ref":"#/components/schemas/UpkQuestionSelectorSLIDER"},{"$ref":"#/components/schemas/UpkQuestionSelectorHIDDEN"}],"title":"Selector"},"configuration":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UpkQuestionConfigurationMC"},{"$ref":"#/components/schemas/UpkQuestionConfigurationTE"},{"$ref":"#/components/schemas/UpkQuestionConfigurationSLIDER"}],"discriminator":{"propertyName":"type","mapping":{"MC":"#/components/schemas/UpkQuestionConfigurationMC","SLIDER":"#/components/schemas/UpkQuestionConfigurationSLIDER","TE":"#/components/schemas/UpkQuestionConfigurationTE"}}},{"type":"null"}],"title":"Configuration"},"validation":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionValidation"},{"type":"null"}]},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]},"categories":{"items":{"$ref":"#/components/schemas/Category"},"type":"array","title":"Categories","description":"Categories associated with this question"},"explanation_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Template","description":"Human-readable template for explaining how a user's answer to this question affects eligibility","examples":["The company that administers your employer's retirement plan is {answer}."]},"explanation_fragment_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Fragment Template","description":"A very short, natural-language explanation fragment that can be combined with others into a single sentence","examples":["whose employer's retirement plan is {answer}"]},"task_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Task Count","description":"The number of live Tasks that use this UPK Question","examples":[47]},"task_score":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Task Score","description":"GRL's internal ranked score for the UPK Question","examples":[0.11175522477414712]},"marketplace_task_count":{"anyOf":[{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object"},{"type":"null"}],"title":"Marketplace Task Count","description":"The number of live Tasks that use this UPK Question per marketplace","examples":[{"d":23,"s":24}]}},"type":"object","required":["question_type","country_iso","language_iso","question_text"],"title":"UpkQuestionOut","example":{"categories":[{"adwords_vertical_id":"396","label":"Politics","parent_uuid":"f66dddba61424ce5be2a38731450a0e1","path":"/News/Politics","uuid":"87b6d819f3ca4815bf1f135b1e829cc6"}],"choices":[{"choice_id":"1","choice_text":"Yes","exclusive":false,"order":0},{"choice_id":"2","choice_text":"No","exclusive":false,"order":1}],"country_iso":"us","importance":{"marketplace_task_count":{"d":9,"s":20,"w":20},"task_count":49,"task_score":3.3401743283265684},"language_iso":"eng","marketplace_task_count":{"d":9,"s":20,"w":20},"question_id":"fb20fd4773304500b39c4f6de0012a5a","question_text":"Are you registered to vote at your present address, or not?","question_type":"MC","selector":"SA","task_count":49,"task_score":3.3401743283265684}},"UpkQuestionResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"questions":{"items":{"$ref":"#/components/schemas/UpkQuestionOut"},"type":"array","title":"Questions"},"consent_questions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Consent Questions","description":"For internal use"},"special_questions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Special Questions","description":"For internal use"},"count":{"type":"integer","minimum":0.0,"title":"Count","description":"The number of questions returned"}},"type":"object","required":["status","questions","count"],"title":"UpkQuestionResponse"},"UpkQuestionSelectorHIDDEN":{"type":"string","enum":["HIDDEN"],"title":"UpkQuestionSelectorHIDDEN"},"UpkQuestionSelectorMC":{"type":"string","enum":["SA","MA","DL","SB","MSB"],"title":"UpkQuestionSelectorMC"},"UpkQuestionSelectorSLIDER":{"type":"string","enum":["HSLIDER","VSLIDER"],"title":"UpkQuestionSelectorSLIDER"},"UpkQuestionSelectorTE":{"type":"string","enum":["SL","ML","ETB"],"title":"UpkQuestionSelectorTE"},"UpkQuestionType":{"type":"string","enum":["MC","TE","SLIDER","HIDDEN"],"title":"UpkQuestionType"},"UpkQuestionValidation":{"properties":{"patterns":{"anyOf":[{"items":{"$ref":"#/components/schemas/PatternValidation"},"type":"array","minItems":1},{"type":"null"}],"title":"Patterns"}},"type":"object","required":["patterns"],"title":"UpkQuestionValidation"},"User":{"properties":{"id":{"anyOf":[{"type":"integer","exclusiveMaximum":2147483648.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Id"},"uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Uuid","examples":["8b33426cdc8548708b52b8389ca99125"]},"product":{"anyOf":[{"$ref":"#/components/schemas/Product"},{"type":"null"}]},"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"product_user_id":{"anyOf":[{"type":"string","maxLength":128,"minLength":3},{"type":"null"}],"title":"Product User Id","description":"A unique identifier for each user, which is set by the Supplier. It should not contain any sensitive informationlike email or names, and should avoid using anyincrementing values.","examples":["app-user-9329ebd"]},"blocked":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Blocked","default":false},"created":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created","description":"When the user was created on the GRL platform."},"last_seen":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Seen","description":"When the user was last seen on, or acting on anypart of the GRL platform."},"audit_log":{"anyOf":[{"items":{"$ref":"#/components/schemas/AuditLog"},"type":"array"},{"type":"null"}],"title":"Audit Log"},"transactions":{"anyOf":[{"items":{"$ref":"#/components/schemas/LedgerTransaction"},"type":"array"},{"type":"null"}],"title":"Transactions"},"location_history":{"anyOf":[{"items":{"$ref":"#/components/schemas/GeoIPInformation"},"type":"array"},{"type":"null"}],"title":"Location History"}},"additionalProperties":false,"type":"object","title":"User"},"UserCreateConfig":{"properties":{"min_hourly_create_limit":{"type":"integer","minimum":0.0,"title":"Min Hourly Create Limit","description":"The smallest allowed value for the hourly user create limit.","default":0},"max_hourly_create_limit":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Hourly Create Limit","description":"The largest allowed value for the hourly user create limit. If None, the hourly create limit is unconstrained."}},"type":"object","title":"UserCreateConfig","description":"Stores configuration for the user creation experience.\n\nThe user creation limit is determined dynamically based on the median\n daily completion rate. min_hourly_create_limit &\n max_hourly_create_limit can be used to constrain the dynamically\n determined rate limit within set values."},"UserHealthConfig":{"properties":{"banned_countries":{"items":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},"type":"array","title":"Banned Countries"},"allow_ban_iphist":{"type":"boolean","title":"Allow Ban Iphist","default":true}},"type":"object","title":"UserHealthConfig"},"UserInfo":{"properties":{"user_profile_knowledge":{"items":{"$ref":"#/components/schemas/UserProfileKnowledge"},"type":"array","title":"User Profile Knowledge"},"marketplace_profile_knowledge":{"items":{"$ref":"#/components/schemas/MarketProfileKnowledge"},"type":"array","title":"Marketplace Profile Knowledge"}},"type":"object","title":"UserInfo"},"UserInfoResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"user_profile":{"$ref":"#/components/schemas/UserInfo"}},"type":"object","required":["status","user_profile"],"title":"UserInfoResponse"},"UserLedgerTransactionTaskAdjustment":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI","default":"Task Adjustment"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"bp_adjustment","title":"Tx Type","default":"bp_adjustment"},"tsid":{"type":"string","maxLength":32,"minLength":32,"title":"Tsid","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","amount","tsid","url","amount_string"],"title":"UserLedgerTransactionTaskAdjustment","example":{"amount":-38,"amount_string":"$-0.38","created":"2026-02-18T07:03:18.644340Z","description":"Task Adjustment","tsid":"25d6081840694376b581f392653ac6fd","tx_type":"bp_adjustment","url":"https://fsb.generalresearch.com/d911167a994a470dbd3ded8b26ff431a/status/25d6081840694376b581f392653ac6fd/"}},"UserLedgerTransactionTaskComplete":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI","default":"Task Complete"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"bp_payment","title":"Tx Type","default":"bp_payment"},"tsid":{"type":"string","maxLength":32,"minLength":32,"title":"Tsid","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","amount","tsid","url","amount_string"],"title":"UserLedgerTransactionTaskComplete","description":"In a BP with user wallet enabled, the task-complete transaction would have line items\n for both the credit to the bp_wallet_account and credit to user_account. This\n is the user-detail, so we've only caring about the user's payment.","example":{"amount":38,"amount_string":"$0.38","created":"2026-02-18T07:03:18.644965Z","description":"Task Complete","tsid":"701ce08adc6d475487fba63412811133","tx_type":"bp_payment","url":"https://fsb.generalresearch.com/40894c77ac64432a994c00c1bf997bda/status/701ce08adc6d475487fba63412811133/"}},"UserLedgerTransactionTypeSummary":{"properties":{"entry_count":{"type":"integer","minimum":0.0,"title":"Entry Count","default":0},"min_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Amount","description":"positive or negative USDCent"},"max_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Amount","description":"positive or negative USDCent"},"total_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Amount","description":"positive or negative USDCent"}},"type":"object","title":"UserLedgerTransactionTypeSummary"},"UserLedgerTransactionTypesSummary":{"properties":{"bp_adjustment":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"},"bp_payment":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"},"user_bonus":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"},"user_payout_request":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"}},"type":"object","title":"UserLedgerTransactionTypesSummary"},"UserLedgerTransactionUserBonus":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI","default":"Compensation Bonus"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"user_bonus","title":"Tx Type","default":"user_bonus"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","amount","url","amount_string"],"title":"UserLedgerTransactionUserBonus","example":{"amount":100,"amount_string":"$1.00","created":"2026-02-18T07:03:18.643773Z","description":"Compensation Bonus","tx_type":"user_bonus"}},"UserLedgerTransactionUserPayout":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"user_payout_request","title":"Tx Type","default":"user_payout_request"},"payout_id":{"type":"string","maxLength":32,"minLength":32,"title":"Payout Id","description":"A unique identifier for the payout","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","description","amount","payout_id","url","amount_string"],"title":"UserLedgerTransactionUserPayout","example":{"amount":-5,"amount_string":"$-0.05","created":"2026-02-18T07:03:18.643220Z","description":"HIT Reward","payout_id":"6734d18098a745719c71ccd36e4cbff1","tx_type":"user_payout_request","url":"https://fsb.generalresearch.com/fd768560e9ec4f77aa3d697d9961aa97/cashout/6734d18098a745719c71ccd36e4cbff1/"}},"UserLedgerTransactionsResponse":{"properties":{"page":{"type":"integer","minimum":1.0,"title":"Page","description":"Page number","default":1},"size":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Size","description":"Page size","default":50},"total":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Total","description":"Total number of results"},"transactions":{"items":{"oneOf":[{"$ref":"#/components/schemas/UserLedgerTransactionUserPayout"},{"$ref":"#/components/schemas/UserLedgerTransactionUserBonus"},{"$ref":"#/components/schemas/UserLedgerTransactionTaskAdjustment"},{"$ref":"#/components/schemas/UserLedgerTransactionTaskComplete"}],"discriminator":{"propertyName":"tx_type","mapping":{"bp_adjustment":"#/components/schemas/UserLedgerTransactionTaskAdjustment","bp_payment":"#/components/schemas/UserLedgerTransactionTaskComplete","user_bonus":"#/components/schemas/UserLedgerTransactionUserBonus","user_payout_request":"#/components/schemas/UserLedgerTransactionUserPayout"}}},"type":"array","title":"Transactions"},"summary":{"$ref":"#/components/schemas/UserLedgerTransactionTypesSummary"},"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pages","description":"Total number of pages","readOnly":true}},"type":"object","required":["summary","status","pages"],"title":"UserLedgerTransactionsResponse"},"UserProfile":{"properties":{"email_address":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email Address","examples":["contact@mail.com"]},"user":{"$ref":"#/components/schemas/User"},"marketplace_pids":{"additionalProperties":{"type":"string","maxLength":32,"minLength":32},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object","title":"Marketplace Pids","description":"User's PID in marketplaces","examples":[{"c":"b507a2c00c3e481fb82f23655d142198","d":"deffe922063e4b9980206a62c3df2fba","i":"1dd9bd986794444eb97cb921aee5663f"}]},"streaks":{"items":{"$ref":"#/components/schemas/UserStreak"},"type":"array","title":"Streaks"},"email_md5":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Email Md5","description":"MD5 hash of the email address","readOnly":true,"examples":["053fc3d5575362159e0c782abec83ffa"]},"email_sha1":{"anyOf":[{"type":"string","maxLength":40,"minLength":40},{"type":"null"}],"title":"Email Sha1","description":"SHA1 hash of the email address","readOnly":true,"examples":["6280fb76135b3585c0c5403be04844a0f0bae726"]},"email_sha256":{"anyOf":[{"type":"string","maxLength":64,"minLength":64},{"type":"null"}],"title":"Email Sha256","description":"SHA256 hash of the email address","readOnly":true,"examples":["8a098233e750f08de87d6053c06a58724287f34372368b6dc28b7ad4a77f3d39"]}},"additionalProperties":false,"type":"object","required":["user","email_md5","email_sha1","email_sha256"],"title":"UserProfile"},"UserProfileKnowledge":{"properties":{"property_id":{"type":"string","title":"Property Id"},"property_label":{"type":"string","title":"Property Label"},"translation":{"type":"string","title":"Translation"},"answer":{"items":{"$ref":"#/components/schemas/UserProfileKnowledgeAnswer"},"type":"array","title":"Answer"},"created":{"type":"string","format":"date-time","title":"Created","description":"When the User submitted this Profiling data"}},"type":"object","required":["property_id","property_label","translation","created"],"title":"UserProfileKnowledge"},"UserProfileKnowledgeAnswer":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"translation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Translation"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value"}},"type":"object","title":"UserProfileKnowledgeAnswer"},"UserProfileResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"user_profile":{"$ref":"#/components/schemas/UserProfile"}},"type":"object","required":["status","user_profile"],"title":"UserProfileResponse"},"UserProfileUpdateRequest":{"properties":{"email_address":{"type":"string","format":"email","title":"Email Address","examples":["contact@mail.com"]}},"additionalProperties":false,"type":"object","required":["email_address"],"title":"UserProfileUpdateRequest"},"UserProfilesResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"user_profiles":{"items":{"$ref":"#/components/schemas/UserProfile"},"type":"array","title":"User Profiles"}},"type":"object","required":["status","user_profiles"],"title":"UserProfilesResponse"},"UserQuestionAnswerIn":{"properties":{"question_id":{"type":"string","maxLength":32,"minLength":32,"title":"Question Id","examples":["fb20fd4773304500b39c4f6de0012a5a"]},"answer":{"items":{"type":"string","maxLength":5000,"minLength":1},"type":"array","maxItems":10,"minItems":1,"title":"Answer","description":"The user's answers to this question. Must pass the choice_id if the question is a Multiple Choice, or the actual text if the question is Text Entry","examples":[["1"]]}},"additionalProperties":false,"type":"object","required":["question_id","answer"],"title":"UserQuestionAnswerIn","description":"Send the answers to one or more questions for a user. A question is\nuniquely specified by the question_id key. The answer is: the choice_id\nif the question_type is \"MC\" the actual entered text if the\nquestion_type is \"TE\"\n\nTODO: look up the question_type from the question_id to apply MC or\n TE specific validation on the answer(s)"},"UserStreak":{"properties":{"country_iso":{"type":"string","title":"Country Iso"},"period":{"$ref":"#/components/schemas/StreakPeriod"},"fulfillment":{"$ref":"#/components/schemas/StreakFulfillment"},"current_streak":{"type":"integer","minimum":0.0,"title":"Current Streak"},"longest_streak":{"type":"integer","minimum":0.0,"title":"Longest Streak"},"state":{"$ref":"#/components/schemas/StreakState"},"last_fulfilled_period_start":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Last Fulfilled Period Start"},"timezone_name":{"type":"string","title":"Timezone Name","readOnly":true},"current_period_bounds":{"prefixItems":[{"type":"string","format":"date-time"},{"type":"string","format":"date-time"}],"type":"array","maxItems":2,"minItems":2,"title":"Current Period Bounds","readOnly":true},"last_fulfilled_period_bounds":{"anyOf":[{"prefixItems":[{"type":"string","format":"date-time"},{"type":"string","format":"date-time"}],"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Last Fulfilled Period Bounds","readOnly":true},"time_remaining_in_period":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Time Remaining In Period","readOnly":true}},"additionalProperties":false,"type":"object","required":["country_iso","period","fulfillment","current_streak","longest_streak","state","timezone_name","current_period_bounds","last_fulfilled_period_bounds","time_remaining_in_period"],"title":"UserStreak"},"UserType":{"type":"string","enum":["business","cafe","cellular","college","content_delivery_network","consumer_privacy_network","government","hosting","library","military","residential","router","school","search_engine_spider","traveler"],"title":"UserType"},"UserWalletBalance":{"properties":{"amount":{"type":"integer","title":"Amount","description":"(USD cents) The amount in the user's wallet."},"redeemable_amount":{"type":"integer","minimum":0.0,"title":"Redeemable Amount","description":"(USD cents) The amount in the user's wallet this is currently redeemable."},"payout_format":{"type":"string","title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]},"amount_string":{"type":"string","title":"Amount String","description":"The 'amount' with the payout_format applied. Can be displayed to the user."},"redeemable_amount_string":{"type":"string","title":"Redeemable Amount String","description":"The 'redeemable_amount' with the payout_format applied. Can be displayed to the user."}},"type":"object","required":["amount","redeemable_amount","payout_format","amount_string","redeemable_amount_string"],"title":"UserWalletBalance","example":{"amount":123,"amount_string":"1230 Points","payout_format":"{payout*10:,.0f} Points","redeemable_amount":100,"redeemable_amount_string":"1000 Points"}},"UserWalletBalanceResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"wallet":{"$ref":"#/components/schemas/UserWalletBalance"}},"type":"object","required":["status","wallet"],"title":"UserWalletBalanceResponse"},"UserWalletConfig":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"If enabled, the users' wallets are managed.","default":false},"amt":{"type":"boolean","title":"Amt","description":"Uses Amazon Mechanical Turk","default":false},"supported_payout_types":{"items":{"$ref":"#/components/schemas/PayoutType"},"type":"array","uniqueItems":true,"title":"Supported Payout Types"},"min_cashout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Cashout","description":"Minimum cashout amount. If enabled is True and no min_cashout is set, will default to $0.01.","examples":["10.00"]}},"type":"object","title":"UserWalletConfig","description":"Stores configuration for the user wallet handling"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WXETOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/WXETOfferwallBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"WXETOfferwall","description":"Returns buckets from WXET as single tasks\nOfferwall code: `55a4e1a9`"},"WXETOfferwallBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"duration":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Duration","description":"The bucket's expected duration, in seconds"},"min_payout":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Min Payout","description":"The bucket's min payout, in usd cents"}},"additionalProperties":false,"type":"object","required":["id","uri","duration","min_payout"],"title":"WXETOfferwallBucket"},"WXETOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/WXETOfferwall"}},"type":"object","required":["info","offerwall"],"title":"WXETOfferwallResponse"},"WallAdjustedStatus":{"type":"string","enum":["ac","af","ca","cc"],"title":"WallAdjustedStatus"},"WallOut":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"source":{"$ref":"#/components/schemas/Source"},"buyer_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Buyer Id"},"req_survey_id":{"type":"string","maxLength":32,"title":"Req Survey Id"},"started":{"type":"string","format":"date-time","title":"Started"},"survey_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Survey Id"},"finished":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished"},"status":{"anyOf":[{"$ref":"#/components/schemas/Status"},{"type":"null"}]},"status_code_1":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"__High level status code for outcome of the session.__\nThis should only be NULL if the Status is ABANDON or TIMEOUT\n\nAllowed values: \n - __BUYER_FAIL__: User terminated in buyer survey\n - __BUYER_QUALITY_FAIL__: User terminated in buyer survey for quality reasons\n - __PS_FAIL__: User failed in marketplace's prescreener\n - __PS_QUALITY__: User rejected by marketplace for quality reasons\n - __PS_BLOCKED__: User is explicitly blocked by the marketplace. Note: on some marketplaces, users can have multiple PS_QUALITY terminations and still complete surveys.\n - __PS_OVERQUOTA__: User rejected by marketplace for over quota\n - __PS_DUPLICATE__: User rejected by marketplace for duplicate\n - __GRS_FAIL__: The user failed within the GRS Platform\n - __GRS_QUALITY_FAIL__: The user failed within the GRS Platform for quality reasons\n - __GRS_ABANDON__: The user abandoned/timed out within the GRS Platform\n - __PS_ABANDON__: The user abandoned/timed out within the marketplace's pre-screen system. Note: On most marketplaces, we have no way of distinguishing between this and BUYER_ABANDON. BUYER_ABANDON is used as the default, unless we know it is PS_ABANDON.\n - __BUYER_ABANDON__: The user abandoned/timed out within the client survey\n - __UNKNOWN__: The status code is not documented\n - __COMPLETE__: The user completed the task successfully\n - __MARKETPLACE_FAIL__: Something was wrong upon the user redirecting from the marketplace, e.g. no postback received, or url hashing failures.\n - __SESSION_START_FAIL__: User failed before being sent into a marketplace\n - __SESSION_CONTINUE_FAIL__: User failed between attempts\n - __SESSION_START_QUALITY_FAIL__: User failed before being sent into a marketplace for \"security\" reasons\n - __SESSION_CONTINUE_QUALITY_FAIL__: User failed between attempts for \"security\" reasons","examples":["COMPLETE"]},"status_code_2":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"This should be set if the Wall.status_code_1 is MARKETPLACE_FAIL\n\nAllowed values: \n - __URL_HASHING_CHECK_FAILED__: The redirect URL (coming back from the marketplace) failed hashing checks\n - __BROKEN_REDIRECT__: The redirect URL was missing required query params or was unparseable\n - __INVALID_REDIRECT__: The redirect URL was invalid or inconsistent in some way and as a result we could not determine the outcome. This could be if a redirect received did not match the user's most recent attempt.\n - __INVALID_MARKETPLACE_POSTBACK__: The redirect indicated a complete, but no/invalid Postback was received from the marketplace\n - __NO_MARKETPLACE_POSTBACK__: No/invalid Postback was received from the marketplace. Used in cases where the redirect does not contain a status.\n - __COMPLETE_TOO_FAST__: The marketplace indicates the user completed the survey, but we don't think this is valid due to speeding. Generally this cutoff is the 95th percentile of our calculated CompletionTime survey stat.\n - __INTERNAL_ERROR__: Something happened during the handling of this redirect (on our side)","examples":[null]},"ext_status_code_1":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Ext Status Code 1"},"ext_status_code_2":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Ext Status Code 2"},"ext_status_code_3":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Ext Status Code 3"},"report_value":{"anyOf":[{"$ref":"#/components/schemas/ReportValue"},{"type":"null"}]},"report_notes":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Report Notes"},"adjusted_status":{"anyOf":[{"$ref":"#/components/schemas/WallAdjustedStatus"},{"type":"null"}]},"adjusted_timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Adjusted Timestamp"},"user_cpi":{"type":"integer","title":"User Cpi","description":"\n The amount the user would earn from completing this task, if the status was a complete.\n If the BP has no payout xform, the user_cpi is None. This is analogous to the session's\n user_payout.\n ","examples":[123]},"user_cpi_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Cpi String","description":"If a payout transformation is configured on this account, this is the amount to display to the user","examples":["123 Points"]}},"additionalProperties":false,"type":"object","required":["source","req_survey_id"],"title":"WallOut"},"WallStatusCode2":{"type":"integer","enum":[12,16,17,13,18,14,15],"title":"WallStatusCode2","description":"This should be set if the Wall.status_code_1 is MARKETPLACE_FAIL"},"YieldManConfig":{"properties":{"category_request":{"$ref":"#/components/schemas/OfferWallCategoryRequest"},"scoring_params":{"$ref":"#/components/schemas/OfferWallRequestYieldmanParams"}},"type":"object","title":"YieldManConfig"}}},"tags":[{"name":"Offerwall","description":"Generate and retrieve various offerwall groupings. These results should be called \"on the \n fly\" just before presenting the results to a respondent. Results greater than 3 minutes old should not be \n presented to the respondent. When a respondent takes any action on a generated offerwall (they go into a \n bucket), the offerwall should be discarded. Any subsequent bucket entrances will fail. The following reserved \n are reserved keywords. However, any additional query parameter that is provided, will be returned back in the \n TaskResponse response in the kwargs attribute.\n\n {'b', 'bp_user_id', 'bpuid', 'country_codes', 'country', 'cpi', 'currency', \n 'description', 'duration', 'entry_link', 'i', 'idx', 'info', 'ip', 'kwargs',\n 'l', 'lang_codes', 'languages', 'loi', 'name', 'payout', 'product_id', \n 'quality', 'quality_category', 'req_loi', 'status', 'task_uri', 'tasks', \n 'tsid', 'uri', 'url', 'country_iso', 'format', 'behavior'}"},{"name":"Status","description":"Retrieving the status of respondent attempts, either by brokerage account filtering, or a specific Task Status ID (TSID) that is provided in the redirect."}]} \ No newline at end of file
+{"openapi":"3.1.0","info":{"title":"General Research Full Service Brokerage API","version":"1.2.0"},"servers":[{"url":"https://fsb.generalresearch.com/","description":"Production environment"}],"paths":{"/{product_id}/offerwall/b145b803/":{"get":{"tags":["Offerwall"],"summary":"Topn Plus Offerwall","description":"Same as the TopNOfferWall, but the buckets include contents.","operationId":"TopN_Plus_Offerwall__product_id__offerwall_b145b803__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopNPlusOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/d48cce47/":{"get":{"tags":["Offerwall"],"summary":"Topn Plus Block Offerwall","description":"Same as the TopNOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.","operationId":"TopN_Plus_Block_Offerwall__product_id__offerwall_d48cce47__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopNPlusBlockOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/1e5f0af8/":{"get":{"tags":["Offerwall"],"summary":"Topn Plus Block Recontact Offerwall","description":"Same as the TopNOfferWall, but the buckets include contents, no buckets\nare returned if the user is blocked, and each bucket includes a\n`is_recontact` key.","operationId":"TopN_Plus_Block_Recontact_Offerwall__product_id__offerwall_1e5f0af8__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopNPlusBlockRecontactOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/5481f322/":{"get":{"tags":["Offerwall"],"summary":"Starwall Plus Offerwall","description":"Same as the StarwallOfferWall, but the buckets include contents.","operationId":"Starwall_Plus_Offerwall__product_id__offerwall_5481f322__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarwallPlusOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/7fa1b3f4/":{"get":{"tags":["Offerwall"],"summary":"Starwall Plus Block Offerwall","description":"Same as the StarwallOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.","operationId":"Starwall_Plus_Block_Offerwall__product_id__offerwall_7fa1b3f4__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarwallPlusBlockOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/630db2a4/":{"get":{"tags":["Offerwall"],"summary":"Starwall Plus Block Recontact Offerwall","description":"Same as the StarwallOfferWall, but the buckets include contents, no buckets\nare returned if the user is blocked, and each bucket includes a\n`is_recontact` key.","operationId":"Starwall_Plus_Block_Recontact_Offerwall__product_id__offerwall_630db2a4__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":3,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"split_by","in":"query","required":false,"schema":{"enum":["payout","duration"],"type":"string","description":"Cluster tasks by payout or duration","default":"payout","title":"Split By"},"description":"Cluster tasks by payout or duration"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarwallPlusBlockRecontactOfferWallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/5fa23085/":{"get":{"tags":["Offerwall"],"summary":"Marketplace Offerwall","description":"Returns buckets grouped by marketplace, one per marketplace, with the\ntasks ordered by quality.","operationId":"Marketplace_Offerwall__product_id__offerwall_5fa23085__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":3,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/6f27b1ae/":{"get":{"tags":["Offerwall"],"summary":"One Shot Offerwall","description":"Each bucket has only 1 single task, and only basic info is returned\n about each bucket.","operationId":"One_Shot_Offerwall__product_id__offerwall_6f27b1ae__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":8,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"sources","in":"query","required":false,"schema":{"type":"array","uniqueItems":true,"items":{"$ref":"#/components/schemas/Source"},"description":"Restrict tasks to those from these marketplaces only.","title":"Sources"},"description":"Restrict tasks to those from these marketplaces only."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OneShotOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/55a4e1a9/":{"get":{"tags":["Offerwall"],"summary":"Wxet Offerwall","description":"Each bucket has only 1 single task, and only basic info is returned\n about each bucket.","operationId":"WXET_Offerwall__product_id__offerwall_55a4e1a9__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":8,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WXETOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/37d1da64/":{"get":{"tags":["Offerwall"],"summary":"Offerwall Softpair","description":"This offerwall contains tasks for which the user has a conditional\neligibility. The questions that a user must answer to determine the\neligibility are included within each bucket. Additionally, the question\ndefinitions are included for convenience.","operationId":"offerwall_softpair__product_id__offerwall_37d1da64__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":12,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":1,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"max_options","in":"query","required":false,"schema":{"type":"integer","description":"Max number of options an allowed question can have (allowed to be asked)","default":40,"title":"Max Options"},"description":"Max number of options an allowed question can have (allowed to be asked)"},{"name":"max_questions","in":"query","required":false,"schema":{"type":"integer","description":"Max number of missing questions on a single bin","default":3,"title":"Max Questions"},"description":"Max number of missing questions on a single bin"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/37d1da64/{offerwall_id}/":{"post":{"tags":["Offerwall"],"summary":"Offerwall Softpair Post","description":"This is a custom endpoint for a softpair-style offerwall that allows\nyou to update profiling answers and then immediately get back the\nupdated offerwall","operationId":"offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"offerwall_id","in":"path","required":true,"schema":{"type":"string","description":"The offerwall ID the user is interacting with","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"],"title":"Offerwall Id"},"description":"The offerwall ID the user is interacting with"},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A session id (uuid4.hex)","examples":["dd6aa32cfe834839a80195563f528337"],"title":"Session Id"},"description":"A session id (uuid4.hex)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/7a89dcdb/":{"get":{"tags":["Offerwall"],"summary":"Offerwall Softpair Block","description":"This offerwall contains tasks for which the user has a conditional\neligibility. The questions that a user must answer to determine the\neligibility are included within each bucket. Additionally, the question\ndefinitions are included for convenience.\nNo buckets are returned if the user is blocked.","operationId":"offerwall_softpair_block__product_id__offerwall_7a89dcdb__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"languages","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)","title":"Languages"},"description":"Respondent's desired languages (ISO 639-2/B, lowercase)"},{"name":"behavior","in":"query","required":false,"schema":{"type":"string","maxLength":12,"description":"Allows using custom scoring functions. Please discuss directly with GRL.","title":"Behavior"},"description":"Allows using custom scoring functions. Please discuss directly with GRL."},{"name":"min_payout","in":"query","required":false,"schema":{"type":"string","description":"Decimal representation of the minimum amount of USD that any of the tasks will pay","examples":["1.23"],"title":"Min Payout"},"description":"Decimal representation of the minimum amount of USD that any of the tasks will pay"},{"name":"duration","in":"query","required":false,"schema":{"type":"integer","description":"Maximum length of desired task (in seconds).","title":"Duration"},"description":"Maximum length of desired task (in seconds)."},{"name":"n_bins","in":"query","required":false,"schema":{"type":"integer","description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split.","default":12,"title":"N Bins"},"description":"Number of bins requested in the offerwall. If n_bins=1 there is no grouping and you get all \n duration + payout metrics on across all (as shown by the availability_count).\n n_bins=0 will return back an empty bucket array, however, the availability_count will still show \n the total opportunities available for that bpuid + passed in parameter settings.\n n_bins=∞ (or any positive integer) will return back the total number of bins capable of being uniquely split."},{"name":"min_bin_size","in":"query","required":false,"schema":{"type":"integer","description":"Minimum number of tasks that need to be in a bucket","default":1,"title":"Min Bin Size"},"description":"Minimum number of tasks that need to be in a bucket"},{"name":"max_options","in":"query","required":false,"schema":{"type":"integer","description":"Max number of options an allowed question can have (allowed to be asked)","default":40,"title":"Max Options"},"description":"Max number of options an allowed question can have (allowed to be asked)"},{"name":"max_questions","in":"query","required":false,"schema":{"type":"integer","description":"Max number of missing questions on a single bin","default":3,"title":"Max Questions"},"description":"Max number of missing questions on a single bin"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/offerwall/7a89dcdb/{offerwall_id}/":{"post":{"tags":["Offerwall"],"summary":"Offerwall Softpair Block Post","description":"This is a custom endpoint for a softpair-style offerwall that allows\nyou to update profiling answers and then immediately get back the\nupdated offerwall","operationId":"offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"offerwall_id","in":"path","required":true,"schema":{"type":"string","description":"The offerwall ID the user is interacting with","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"],"title":"Offerwall Id"},"description":"The offerwall ID the user is interacting with"},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A session id (uuid4.hex)","examples":["dd6aa32cfe834839a80195563f528337"],"title":"Session Id"},"description":"A session id (uuid4.hex)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftPairOfferwallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/status/{tsid}/":{"get":{"tags":["Status"],"summary":"Get Task Status","description":"Retrieve the status of a session by a specific Task Status ID (`tsid`)\nthat is provided in the redirect.\n\nGiven a `tsid`, get back the status of the wall event. This endpoint\nconflates the idea of a wall event and a session, but for these\npurposes, the status and payout of the last wall event in a session\nequals the status and payout for the session.","operationId":"Get_Task_Status__product_id__status__tsid___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"tsid","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Task Status ID","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"description":"A unique identifier for the session"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskStatusResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusInfoResponseFail"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusInfoResponseFail"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusInfoResponseFail"}}},"description":"Internal Server Error"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/status/":{"get":{"tags":["Status"],"summary":"List Task Statuses","operationId":"List_Task_Statuses__product_id__status__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":false,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Filters the returned task status to only include those done by this user.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Filters the returned task status to only include those done by this user."},{"name":"started_after","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were started after this timestamp. If `NULL`, default is 10 days ago.","examples":["2026-09-08T22:12:19.351267Z",1788819139],"title":"Started After"},"description":"Retrieve sessions which were started after this timestamp. If `NULL`, default is 10 days ago."},{"name":"started_before","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were started before this timestamp. If `NULL`, default is now.","title":"Started Before"},"description":"Retrieve sessions which were started before this timestamp. If `NULL`, default is now."},{"name":"status","in":"query","required":false,"schema":{"type":"integer","description":"Filter for sessions with this status. See Task Status for description of status.","examples":[3],"title":"Status"},"description":"Filter for sessions with this status. See Task Status for description of status."},{"name":"reconciled","in":"query","required":false,"schema":{"type":"boolean","description":"Only retrieve sessions that have been adjusted. If `reconciled` is True, `adjusted_after` is required.","default":false,"title":"Reconciled"},"description":"Only retrieve sessions that have been adjusted. If `reconciled` is True, `adjusted_after` is required."},{"name":"adjusted_after","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were adjusted after this timestamp.","title":"Adjusted After"},"description":"Retrieve sessions which were adjusted after this timestamp."},{"name":"adjusted_before","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"string","format":"date-time"}],"description":"Retrieve sessions which were adjusted before this timestamp. Default is now.","title":"Adjusted Before"},"description":"Retrieve sessions which were adjusted before this timestamp. Default is now."},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated fields to order by","examples":["-started","started"],"default":"-started","title":"Order By"},"description":"Comma-separated fields to order by"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TasksStatusResponse"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponseFailure"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponseFailure"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponseFailure"}}},"description":"Internal Server Error"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/report/":{"post":{"tags":["Report"],"summary":"Report Task","description":"Send a \"Task Report\" for a respondent's latest started survey,\nregardless of the survey's outcome. Task Reports cannot be provided for\ntask attempts by tsid, or through any other method, they must be given\nimmediately after the respondent's task attempt.\n\nIf a latest attempt can't be found, a ReportTaskResponse is still returned.\n\nIf multiple reasons want to be provided, they should be done at the\nsame time. If multiple reports are given for the same latest started\ntask, the note attribute will be overwritten, while the new unique\nreasons will be appended to the task attempt.\n\nTask Report system contributions by client applications are immediately\nleveraged to aid yield management strategies. For those reasons, it's\nimportant that the respondent submits a Task Report as soon as possible\nand applications doesn't offload this request for a later time. Task\nReport timestamps are a critical component of understanding a Task\nexperience for a respondent.\n\nFor the BP to tell us about a bad survey they want to report\nThe POSTed data looks like:\n {\n 'bpuid': '1234',\n 'reasons': [2],\n 'notes': \"This survey was the worst!\"\n }\nReturns {'status': 'success', 'msg': error_msg}","operationId":"report_task__product_id__report__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportTask"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/profiling-questions/":{"get":{"tags":["Profiling Questions"],"summary":"Get Profiling Questions","description":"Gets a list of profiling questions to ask this user. These questions\nare, as of right now, unanswered. Once a question is answered, it\n(and any other question whose answer is inferred from other answers) is\nremoved from the list. The questions returned are ordered by\nimportance (the key task_score) in descending order.","operationId":"get_profiling_questions__product_id__profiling_questions__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"ip","in":"query","required":false,"schema":{"type":"string","description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided.","title":"Ip"},"description":"Respondent's IP address (IPv4 or IPv6). Either 'ip' must be provided, or 'country_iso' must be provided if 'ip' is not provided."},{"name":"country_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"language_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{3}$","description":"Respondent's desired language (ISO 639-2/B, lowercase)","examples":["eng"],"title":"Language Iso"},"description":"Respondent's desired language (ISO 639-2/B, lowercase)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"description":"Number of questions to return. Questions are ordered, so, selects the N most important. If no limit is passed, then the number of questions returned is dynamically calculated by the questions' importance.","title":"Limit"},"description":"Number of questions to return. Questions are ordered, so, selects the N most important. If no limit is passed, then the number of questions returned is dynamically calculated by the questions' importance."},{"name":"is_grs","in":"query","required":false,"schema":{"type":"boolean","description":"If it's the GRS system.","default":false,"title":"Is Grs"},"description":"If it's the GRS system."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpkQuestionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Profiling Questions"],"summary":"Submit Profiling Questions","description":"Send the answers to one or more of these questions for a user. A\nquestion is uniquely specified by the question_id key. The answer is:\nthe choice_id if the question_type is \"MC\" the actual entered text if\nthe question_type is \"TE\"","operationId":"submit_profiling_questions__product_id__profiling_questions__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"session_id","in":"query","required":false,"schema":{"type":"string","description":"The unique identifier for a session in which these questions were asked. Must be a valid UUID. Optional.","title":"Session Id"},"description":"The unique identifier for a session in which these questions were asked. Must be a valid UUID. Optional."},{"name":"async","in":"query","required":false,"schema":{"type":"boolean","description":"For internal use.","default":true,"title":"Async"},"description":"For internal use."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_submit_profiling_questions__product_id__profiling_questions__post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/profiling-info/":{"get":{"tags":["Profiling Questions"],"summary":"Profiling Info","description":"Get UPK Ontology (list of properties, property info, and allowed values)","operationId":"profiling_info__product_id__profiling_info__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"country_iso","in":"query","required":true,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"language_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{3}$","description":"Respondent's desired language (ISO 639-2/B, lowercase)","examples":["eng"],"title":"Language Iso"},"description":"Respondent's desired language (ISO 639-2/B, lowercase)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilingInfoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/user-profile/":{"get":{"tags":["Profiling Questions"],"summary":"User Profile","operationId":"user_profile__product_id__user_profile__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"country_iso","in":"query","required":true,"schema":{"type":"string","pattern":"^[a-z]{2}$","description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)","examples":["us"],"title":"Country Iso"},"description":"Respondent's country code (ISO 3166-1 alpha-2, lowercase)"},{"name":"language_iso","in":"query","required":false,"schema":{"type":"string","pattern":"^[a-z]{3}$","description":"Respondent's desired language (ISO 639-2/B, lowercase)","examples":["eng"],"title":"Language Iso"},"description":"Respondent's desired language (ISO 639-2/B, lowercase)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/user/{product_user_id}/profile/":{"get":{"tags":["Product User"],"summary":"User Profile","operationId":"user_profile__product_id__user__product_user_id__profile__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Product User"],"summary":"User Profile Update","operationId":"user_profile_update__product_id__user__product_user_id__profile__patch","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfileUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/user/by-marketplace-pid/":{"get":{"tags":["Product User"],"summary":"User Profile Filter By Marketplace Pid","operationId":"user_profile_filter_by_marketplace_pid__product_id__user_by_marketplace_pid__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"source","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Source","description":"The marketplace to search"},"description":"The marketplace to search"},{"name":"pid","in":"query","required":true,"schema":{"type":"array","items":{"type":"string","minLength":32,"maxLength":32},"description":"The user's marketplace PID. Supports multiple params","title":"Pid"},"description":"The user's marketplace PID. Supports multiple params"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserProfilesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/leaderboard/timespan/{board_code}/":{"get":{"tags":["Leaderboard"],"summary":"Timespan Leaderboard","operationId":"Timespan_Leaderboard__product_id__leaderboard_timespan__board_code___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"board_code","in":"path","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},"description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},{"name":"freq","in":"query","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},"description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},{"name":"country_iso","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[a-z]{2}$"},{"type":"null"}],"description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.","examples":["us"],"title":"Country Iso"},"description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request."},{"name":"bpuid","in":"query","required":false,"schema":{"type":"string","minLength":3,"maxLength":128,"description":"Brokerage Product User ID. If passed, this results in the filtering of rows to include this user's row, plus rows above and below in rank (up to `limit` rows). Otherwise, the top `limit` rows are returned.","examples":["app-user-9329ebd"],"title":"Bpuid"},"description":"Brokerage Product User ID. If passed, this results in the filtering of rows to include this user's row, plus rows above and below in rank (up to `limit` rows). Otherwise, the top `limit` rows are returned."},{"name":"within_time","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Any local timestamp falling within the desired leaderboard's period. If not passed, uses the country's current time period.","examples":["2024-02-27","2024-02-27T15:30:00"],"title":"Within Time"},"description":"Any local timestamp falling within the desired leaderboard's period. If not passed, uses the country's current time period."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMaximum":5000,"exclusiveMinimum":0,"description":"Max number of rows to return","default":50,"title":"Limit"},"description":"Max number of rows to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/leaderboard/timespan/{board_code}/winners/":{"get":{"tags":["Leaderboard"],"summary":"Leaderboard Winners","description":"Get the Winners of leaderboard contests","operationId":"Leaderboard_Winners__product_id__leaderboard_timespan__board_code__winners__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"board_code","in":"path","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},"description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts"},{"name":"freq","in":"query","required":true,"schema":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},"description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00"},{"name":"country_iso","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[a-z]{2}$"},{"type":"null"}],"description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request.","examples":["us"],"title":"Country Iso"},"description":"Country ISO Code (ISO 3166-1 alpha-2, lowercase) of the requested leaderboard. If not passed, thecountry is determined from the IP address of the HTTP request."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaderboardWinnerResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/{contest_uuid}/user/{product_user_id}/":{"get":{"tags":["Contest"],"summary":"Get Contest User View","description":"Gets a Contest. Includes several keys that are specific to the requesting user:\n e.g. user_winnings, user_amount.","operationId":"Get_Contest_User_View__product_id__contest__contest_uuid__user__product_user_id___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"contest_uuid","in":"path","required":true,"schema":{"type":"string","title":"Contest Uuid"}},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}],"title":"Response Get Contest User View Product Id Contest Contest Uuid User Product User Id Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/user/{product_user_id}/entered/":{"get":{"tags":["Contest"],"summary":"List Contests User Entered","description":"Get contests the requesting user has entered. This includes contests such as milestone\n contests where the user was automatically entered by having a complete for instance.","operationId":"List_Contests_User_Entered__product_id__contest_user__product_user_id__entered__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}]},"title":"Response List Contests User Entered Product Id Contest User Product User Id Entered Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/user/{product_user_id}/eligible/":{"get":{"tags":["Contest"],"summary":"List Contests User Eligible","description":"Get contests the requesting user is eligible for.\nContest eligibility may involve the user's country, which is determined by the ip address\n of THIS request.","operationId":"List_Contests_User_Eligible__product_id__contest_user__product_user_id__eligible__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}]},"title":"Response List Contests User Eligible Product Id Contest User Product User Id Eligible Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/contest/user/{product_user_id}/winner/":{"get":{"tags":["Contest"],"summary":"List Contests User Winner","description":"Get contests the requesting user has won a prize for.","operationId":"List_Contests_User_Winner__product_id__contest_user__product_user_id__winner__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"product_user_id","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/RaffleUserView"},{"$ref":"#/components/schemas/LeaderboardContestUserView"},{"$ref":"#/components/schemas/MilestoneUserView"}]},"title":"Response List Contests User Winner Product Id Contest User Product User Id Winner Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/wallet/":{"get":{"tags":["Wallet"],"summary":"Get User Wallet Balance","description":"Retrieve the current balance of a respondent's wallet balance for display","operationId":"get_user_wallet_balance__product_id__wallet__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserWalletBalanceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/wallets/":{"get":{"tags":["Wallet"],"summary":"Get User Wallets","description":"Retrieve a respondent's wallets and balances for display","operationId":"get_user_wallets__product_id__wallets__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLedgerWallets"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout_methods/":{"get":{"tags":["Wallet"],"summary":"Get Cashout Methods","description":"Retrieve the current available mechanisms that a user can use to retrieve funds.","operationId":"get_cashout_methods__product_id__cashout_methods__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutMethodsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Wallet"],"summary":"Create Cashout Method","description":"A user can only have 1 unique Cashout Method of any type at a time (eg. they can't create multiple paypal\npayout methods). Cashout Methods cannot be edited, they can only be created or deleted. Creating different\nCashout Methods will require type-dependent request data attributes in order to be successfully created.\n\nCurrently only creating paypal or Cash in Mail cashout methods are supported","operationId":"create_cashout_method__product_id__cashout_methods__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CreatePayPalCashoutMethodRequest"},{"$ref":"#/components/schemas/CreateCashMailCashoutMethodRequest"}],"discriminator":{"propertyName":"type","mapping":{"PAYPAL":"#/components/schemas/CreatePayPalCashoutMethodRequest","CASH_IN_MAIL":"#/components/schemas/CreateCashMailCashoutMethodRequest"}},"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutMethodResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout_methods/{cashout_method_id}/":{"delete":{"tags":["Wallet"],"summary":"Delete Cashout Method","description":"Delete a cashout method","operationId":"delete_cashout_method__product_id__cashout_methods__cashout_method_id___delete","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"cashout_method_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"description":"The ID of the cashout method to delete","title":"Cashout Method Id"},"description":"The ID of the cashout method to delete"},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout/":{"post":{"tags":["Wallet"],"summary":"Submit User Cashout","description":"Request a cashout taken from a user's available wallet balance, to be paid via a particular\ncashout method.","operationId":"submit_user_cashout__product_id__cashout__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCashoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutRequestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout/{cashout_id}/":{"get":{"tags":["Wallet"],"summary":"Get Cashout Detail","description":"Retrieve the details for a specific Cashout event","operationId":"get_cashout_detail__product_id__cashout__cashout_id___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"cashout_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"description":"The cashout event ID","title":"Cashout Id"},"description":"The cashout event ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutRequestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/transaction_history/":{"get":{"tags":["Wallet"],"summary":"Get User Transaction History","description":"Return array of user events that altered their wallet balance","operationId":"get_user_transaction_history__product_id__transaction_history__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"bpuid","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":128,"title":"Brokerage Product User ID","description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values.","examples":["app-user-9329ebd"]},"description":"A unique identifier for each user, which is set by the Supplier. Must be consistent across respondent entrances and unique to the platform. It should not contain any sensitive information like email or names, and should avoid using any incrementing values."},{"name":"created_after","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Filter transactions created after this timestamp","examples":["2025-01-01T04:20:00.000000Z"],"title":"Created After"},"description":"Filter transactions created after this timestamp"},{"name":"created_before","in":"query","required":false,"schema":{"type":"string","format":"date-time","description":"Filter transactions created before this timestamp","examples":["2026-09-08T22:12:19.380546Z"],"title":"Created Before"},"description":"Filter transactions created before this timestamp"},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated fields to order by","examples":["-created","created"],"default":"created","title":"Order By"},"description":"Comma-separated fields to order by"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLedgerTransactionsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/cashout_method/{cashout_method_id}/value/":{"get":{"tags":["Wallet"],"summary":"Get Expected Redemption Value","description":"Use this function to get the \"value\" (in local currency, e.g. CAD, BTC) for this\n cashout_method, for amount (in USD cents).","operationId":"get_expected_redemption_value__product_id__cashout_method__cashout_method_id__value__get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"cashout_method_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"description":"The ID of the cashout method","examples":["0d363971792249b1a34586f092819e4b"],"title":"Cashout Method Id"},"description":"The ID of the cashout method"},{"name":"amount","in":"query","required":true,"schema":{"type":"integer","description":"(USD cents) The amount to convert","examples":[100],"title":"Amount"},"description":"(USD cents) The amount to convert"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashoutMethodForeignValueResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/wallet/attempt-credit/":{"post":{"tags":["Wallet"],"summary":"Claim Latest Attempt Credit","description":"Attempt to claim an Attempt Credit from the user's latest Session.","operationId":"claim_latest_attempt_credit__product_id__wallet_attempt_credit__post","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttemptCreditClaimBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttemptCreditClaimResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{product_id}/wallet/attempt-credit/{tsid}/":{"get":{"tags":["Wallet"],"summary":"Get Attempt Credit","description":"Get an Attempt Credit by a user's Session.","operationId":"get_attempt_credit__product_id__wallet_attempt_credit__tsid___get","parameters":[{"name":"product_id","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Brokerage Product ID","description":"The Brokerage Product ID provided by GRL.","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"description":"The Brokerage Product ID provided by GRL."},{"name":"tsid","in":"path","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Task Status ID","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"description":"A unique identifier for the session"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttemptCreditClaimResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/thl/manage_cashout/":{"post":{"tags":["THL"],"summary":"Manage Cashout","operationId":"manage_cashout_thl_manage_cashout__post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManageCashoutBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPayoutEvent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dashboard/inventory/":{"get":{"tags":["Dashboard"],"summary":"Marketplace Inventory","operationId":"marketplace_inventory_dashboard_inventory__get","parameters":[{"name":"marketplace","in":"query","required":true,"schema":{"const":"WXET","type":"string","examples":["WXET"],"title":"Marketplace"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceSummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ws/debug/":{"get":{"tags":["Streams"],"summary":"Websocket Debug Page","operationId":"websocket_debug_page_ws_debug__get","parameters":[{"name":"product_id","in":"query","required":true,"schema":{"type":"string","minLength":32,"maxLength":32,"title":"Product Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ws/events/docs/":{"get":{"tags":["Streams"],"summary":"Websocket Events Docs","description":"WebSocket endpoint: `/ws/events/`\n\nProtocol:\n- Client connects\n- Client sends a SubscribeMessage `{ kind: \"subscribe\", product_id: \"{product_id}\" }`\n- Server sends a PingMessage `{ kind: \"ping\" }`\n- Client must reply a PongMessage: `{ kind: \"pong\" }`\n- Other messages are EventMessage or StatsMessage\n\nClose on missing pong after 20s.","operationId":"websocket_events_docs_ws_events_docs__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/EventMessage"},{"$ref":"#/components/schemas/StatsMessage"},{"$ref":"#/components/schemas/PingMessage"},{"$ref":"#/components/schemas/SubscribeMessage"},{"$ref":"#/components/schemas/PongMessage"}],"title":"Response Websocket Events Docs Ws Events Docs Get"}}}}}}}},"components":{"schemas":{"AccessType":{"type":"string","enum":["residential","mobile","satellite","datacenter","enterprise","unknown"],"title":"AccessType","description":"How the network is used"},"AccountType":{"type":"string","enum":["bp_commission","bp_wallet","user_wallet","user_attempt_credit","cash","revenue","expense","contest_wallet","credit_line","wa_wallet","wa_budget_pool","wa_held","wa_credit_line"],"title":"AccountType"},"AdjustmentType":{"properties":{"amount":{"type":"integer","title":"Amount","description":"The total amount (in USD cents) that the Brokerage Producthas earned within a respective time period from a specificSource of Tasks."},"adjustment":{"$ref":"#/components/schemas/SessionAdjustedStatus","description":" - `ac` = ADJUSTED_TO_COMPLETE\n - `af` = ADJUSTED_TO_FAIL\n - `pa` = PAYOUT_ADJUSTMENT","examples":["af"]}},"type":"object","required":["amount","adjustment"],"title":"AdjustmentType"},"AggregateBySource":{"properties":{"total":{"type":"integer","minimum":0.0,"title":"Total","default":0},"by_source":{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object","title":"By Source"}},"type":"object","title":"AggregateBySource"},"AmtCashoutMethodData":{"properties":{"type":{"type":"string","const":"AMT","title":"Type","default":"AMT"}},"type":"object","title":"AmtCashoutMethodData"},"AttemptCreditClaimBody":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"Bpuid","description":"(product_user_id) The user requesting the claim","examples":["app-user-9329ebd"]}},"type":"object","required":["bpuid"],"title":"AttemptCreditClaimBody"},"AttemptCreditClaimResponse":{"properties":{"amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Amount","description":"(USD cents) The amount given to the user as an attempt credit."}},"type":"object","required":["amount"],"title":"AttemptCreditClaimResponse"},"AuditLog":{"properties":{"id":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Id"},"user_id":{"type":"integer","exclusiveMinimum":0.0,"title":"User Id"},"created":{"type":"string","format":"date-time","title":"Created","description":"When did this event occur","examples":["2026-09-08T22:12:17.882731Z"]},"level":{"$ref":"#/components/schemas/AuditLogLevel","description":"The level of importance for this event. Works the same as python logging levels. It is an integer 0 - 50, and implementers of this field could map it to the predefined levels: (`CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`).This is NOT the same concept as the 'strength' of whatever event happened; it is just for sorting, filtering and display purposes. For e.g. multiple level 20 events != the 'importance' of one level 40 event.","examples":[30]},"event_type":{"type":"string","maxLength":64,"title":"Event Type","examples":["entrance-limit"]},"event_msg":{"anyOf":[{"type":"string","maxLength":256,"minLength":3},{"type":"null"}],"title":"Event Msg","description":"The event message. Could be displayed on user's page"},"event_value":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Event Value","description":"Optionally store a numeric value associated with this event. For e.g. if we recalculate the user's normalized recon rate, and it is 'high', we could store an event like (event_type='recon-rate', event_msg='higher than allowed recon rate' event_value=0.42)","examples":[0.42]}},"type":"object","required":["user_id","level","event_type"],"title":"AuditLog","description":"Table / Model for logging \"actions\" taken by a user or \"events\" that\nare related to a User"},"AuditLogLevel":{"type":"integer","enum":[50,50,40,30,30,20,10,0],"title":"AuditLogLevel"},"Body_offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/UserQuestionAnswerIn"},"type":"array","title":"Answers"}},"type":"object","required":["answers"],"title":"Body_offerwall_softpair_block_post__product_id__offerwall_7a89dcdb__offerwall_id___post"},"Body_offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/UserQuestionAnswerIn"},"type":"array","title":"Answers"}},"type":"object","required":["answers"],"title":"Body_offerwall_softpair_post__product_id__offerwall_37d1da64__offerwall_id___post"},"Body_submit_profiling_questions__product_id__profiling_questions__post":{"properties":{"answers":{"items":{"$ref":"#/components/schemas/UserQuestionAnswerIn"},"type":"array","title":"Answers"}},"type":"object","required":["answers"],"title":"Body_submit_profiling_questions__product_id__profiling_questions__post"},"BrokerageProductPayoutEvent":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Payout Event Unique Identifier","examples":["9453cd076713426cb68d05591c7145aa"]},"debit_account_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Debit Account Uuid","description":"The LedgerAccount.uuid that money is being requested from. Thie User or Brokerage Product is retrievable through the LedgerAccount.reference_uuid","examples":["18298cb1583846fbb06e4747b5310693"]},"cashout_method_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Cashout Method Uuid","description":"References a row in the account_cashoutmethod table. This is the cashout method that was used to request this payout. (A cashout is the same thing as a payout)","examples":["a6dc1fc1bf934557b952f253dee12813"]},"created":{"type":"string","format":"date-time","title":"Created"},"amount":{"type":"integer","exclusiveMaximum":9.223372036854776e+18,"exclusiveMinimum":0.0,"title":"Amount","description":"The USDCent amount int. This cannot be 0 or negative","examples":[531]},"status":{"anyOf":[{"$ref":"#/components/schemas/PayoutStatus"},{"type":"null"}],"description":" - `PENDING` = PENDING\n - `APPROVED` = APPROVED\n - `REJECTED` = REJECTED\n - `CANCELLED` = CANCELLED\n - `FAILED` = FAILED\n - `COMPLETE` = COMPLETE","default":"PENDING","examples":["COMPLETE"]},"ext_ref_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ext Ref Id"},"payout_type":{"$ref":"#/components/schemas/PayoutType","description":" - `PAYPAL` = PAYPAL\n - `TANGO` = TANGO\n - `DWOLLA` = DWOLLA\n - `ACH` = ACH\n - `WIRE` = WIRE\n - `CASH_IN_MAIL` = CASH_IN_MAIL\n - `PRIZE` = PRIZE\n - `AMT` = AMT\n - `AMT_BONUS` = AMT_BONUS\n - `AMT_ASSIGNMENT` = AMT_HIT","examples":["ACH"]},"request_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Request Data","description":"Stores payout-type-specific information that is used to request this payout from the external provider."},"order_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"$ref":"#/components/schemas/CashMailOrderData"},{"type":"null"}],"title":"Order Data","description":"Stores payout-type-specific order information that is returned from the external payout provider."},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"The Brokerage Product that was paid out","examples":["1108d053e4fa47c5b0dbdcd03a7981e7"]},"method":{"$ref":"#/components/schemas/PayoutType","description":" - `PAYPAL` = PAYPAL\n - `TANGO` = TANGO\n - `DWOLLA` = DWOLLA\n - `ACH` = ACH\n - `WIRE` = WIRE\n - `CASH_IN_MAIL` = CASH_IN_MAIL\n - `PRIZE` = PRIZE\n - `AMT` = AMT\n - `AMT_BONUS` = AMT_BONUS\n - `AMT_ASSIGNMENT` = AMT_HIT","readOnly":true,"examples":["ACH"]},"amount_usd":{"type":"integer","minimum":0.0,"title":"Amount Usd","readOnly":true,"examples":["$10,000.000"]},"amount_usd_str":{"type":"string","title":"Amount Usd Str","readOnly":true,"examples":["$10,000.000"]}},"type":"object","required":["debit_account_uuid","cashout_method_uuid","amount","payout_type","product_id","method","amount_usd","amount_usd_str"],"title":"BrokerageProductPayoutEvent","description":"The amount\n\n- created: When the Brokerage Product was paid out"},"BucketTask":{"properties":{"id":{"type":"string","maxLength":32,"minLength":1,"title":"Id","description":"The internal task id for this task within the marketplace","examples":["6ov9jz3"]},"id_code":{"type":"string","maxLength":35,"minLength":3,"pattern":"^[a-z]{1,2}\\:.*","title":"Id Code","description":"The namespaced task id for this task within the marketplace","examples":["o:6ov9jz3"]},"source":{"$ref":"#/components/schemas/Source","examples":["o"]},"loi":{"type":"integer","maximum":5400.0,"exclusiveMinimum":1.0,"title":"Loi","description":"expected loi in seconds","examples":[612]},"payout":{"type":"integer","exclusiveMinimum":1.0,"title":"Payout","description":"integer cents","examples":[123]}},"type":"object","required":["id","id_code","source","loi","payout"],"title":"BucketTask","description":"This represents one of the \"tasks\" within a bucket's ordered list of tasks."},"Cardinality":{"type":"string","enum":["*","?"],"title":"Cardinality"},"CashMailCashoutMethodData":{"properties":{"type":{"type":"string","const":"CASH_IN_MAIL","title":"Type","default":"CASH_IN_MAIL"},"delivery_address":{"$ref":"#/components/schemas/USDeliveryAddress","description":"Delivery address where payment should be sent"}},"type":"object","required":["delivery_address"],"title":"CashMailCashoutMethodData"},"CashMailOrderData":{"properties":{"type":{"type":"string","const":"CASH_IN_MAIL","title":"Type","default":"CASH_IN_MAIL"},"shipping_cost":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Shipping Cost","description":"(USD cents) The shipping cost. This amount get charged to the BP."},"tracking_number":{"anyOf":[{"type":"string","maxLength":50,"minLength":1},{"type":"null"}],"title":"Tracking Number"},"shipping_method":{"anyOf":[{"$ref":"#/components/schemas/ShippingMethod","maxLength":50,"minLength":1},{"type":"null"}],"description":"Standard, express, etc."},"carrier":{"anyOf":[{"$ref":"#/components/schemas/ShippingCarrier","maxLength":50,"minLength":1},{"type":"null"}],"description":"Name of the shipping company, e.g., USPS, FedEx, DHL"},"ship_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ship Date"},"estimated_delivery_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Estimated Delivery Date"},"delivery_status":{"anyOf":[{"$ref":"#/components/schemas/DeliveryStatus","maxLength":50,"minLength":1},{"type":"null"}],"description":"Current status of delivery, e.g., pending, in transit, delivered"},"last_updated":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Updated","description":"Timestamp of the last status update"}},"type":"object","required":["shipping_cost"],"title":"CashMailOrderData"},"CashoutMethodForeignValue":{"properties":{"value":{"type":"integer","minimum":0.0,"title":"Value","description":"Value of the redemption in the currency's smallest unit."},"currency":{"$ref":"#/components/schemas/RedemptionCurrency","description":"Supported Currencies for Foreign Redemptions\n\nAllowed values: \n - __USD__ *(USD)*: US Dollars. Smallest Unit: Cents.\n - __CAD__ *(CAD)*: Canadian Dollars. Smallest Unit: Cents.\n - __GBP__ *(GBP)*: British Pounds. Smallest Unit: Pence.\n - __EUR__ *(EUR)*: Euros. Smallest Unit: Cents.\n - __INR__ *(INR)*: Indian Rupees. Smallest Unit: Paise.\n - __AUD__ *(AUD)*: Australian Dollars. Smallest Unit: Cents.\n - __PLN__ *(PLN)*: Polish Zloty. Smallest Unit: Grosz.\n - __SEK__ *(SEK)*: Swedish Krona. Smallest Unit: Öre.\n - __SGD__ *(SGD)*: Singapore Dollars. Smallest Unit: Cents.\n - __MXN__ *(MXN)*: Mexican Pesos. Smallest Unit: Centavos."},"value_string":{"type":"string","title":"Value String","description":"A string representation of the value in the currency."}},"type":"object","required":["value","currency","value_string"],"title":"CashoutMethodForeignValue","description":"Shows the expected value of a redemption in a foreign currency.","example":{"currency":"CAD","value":"138","value_string":"$1.38 CAD"}},"CashoutMethodForeignValueResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout_method_value":{"$ref":"#/components/schemas/CashoutMethodForeignValue"}},"type":"object","required":["status","cashout_method_value"],"title":"CashoutMethodForeignValueResponse"},"CashoutMethodOut":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique ID for this cashout method"},"currency":{"type":"string","const":"USD","title":"Currency","description":"The currency of the cashout. Only USD is supported.","default":"USD"},"original_currency":{"anyOf":[{"$ref":"#/components/schemas/Currency"},{"type":"null"}],"description":"The base currency of the money paid out. This is used for e.g. sending an Amazon UK gift card"},"data":{"oneOf":[{"$ref":"#/components/schemas/PaypalCashoutMethodData"},{"$ref":"#/components/schemas/TangoCashoutMethodData"},{"$ref":"#/components/schemas/CashMailCashoutMethodData"},{"$ref":"#/components/schemas/AmtCashoutMethodData"}],"title":"Data","discriminator":{"propertyName":"type","mapping":{"AMT":"#/components/schemas/AmtCashoutMethodData","CASH_IN_MAIL":"#/components/schemas/CashMailCashoutMethodData","PAYPAL":"#/components/schemas/PaypalCashoutMethodData","TANGO":"#/components/schemas/TangoCashoutMethodData"}}},"description":{"type":"string","title":"Description","description":"The description of the cashout method.","default":""},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"Link to an image to display"},"max_value":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Value","description":"(In lowest unit of the original_currency), The maximum amount that can be cashed out in one transaction."},"min_value":{"type":"integer","minimum":0.0,"title":"Min Value","description":"(In lowest unit of the original_currency), The minimum amount that can be cashed out in one transaction."},"name":{"type":"string","title":"Name","description":"A descriptive name for the cashout method."},"type":{"$ref":"#/components/schemas/PayoutType","description":"The method in which the requested payout is delivered.\n\nAllowed values: \n - __PAYPAL__ *(PAYPAL)*: User is paid out to their personal PayPal email address\n - __TANGO__ *(TANGO)*: User is paid out via a Tango Gift Card\n - __DWOLLA__ *(DWOLLA)*: DWOLLA\n - __ACH__ *(ACH)*: A payment is made to a bank account using ACH\n - __WIRE__ *(WIRE)*: A payment is made to a bank account using ACH\n - __CASH_IN_MAIL__ *(CASH_IN_MAIL)*: A payment is made in cash and mailed to the user.\n - __PRIZE__ *(PRIZE)*: A payment is made as a prize with some monetary value\n - __AMT__ *(AMT)*: This is used to designate either AMT_BONUS or AMT_HIT\n - __AMT_BONUS__ *(AMT_BONUS)*: Amazon Mechanical Turk as a Bonus\n - __AMT_ASSIGNMENT__ *(AMT_HIT)*: Amazon Mechanical Turk for a HIT"},"ext_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ext Id","description":"An external ID. Can be shown to a user to disambiguate a user's possibly multiple methods"},"usd_exchange_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Usd Exchange Rate"},"max_value_usd":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Value Usd","description":"(In lowest unit of USD), The maximum amount that can be cashed out in one transaction."},"min_value_usd":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Min Value Usd","description":"(In lowest unit of USD), The minimum amount that can be cashed out in one transaction."},"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"product_user_id":{"anyOf":[{"type":"string","maxLength":128,"minLength":3},{"type":"null"}],"title":"Product User Id","description":"A unique identifier for each user, which is set by the Supplier. It should not contain any sensitive informationlike email or names, and should avoid using anyincrementing values.","examples":["app-user-9329ebd"]}},"type":"object","required":["id","data","max_value","min_value","name","type"],"title":"CashoutMethodOut","example":{"bpid":"6a3ddfb747344bbc93efadf1c3a16e1a","currency":"USD","data":{"disclaimer":"...","terms":"..."},"description":"...","id":"941d489c3ce04eb39a0ddb7f8f75db74","image_url":"https://d30s7yzk2az89n.cloudfront.net/images/brands/b238587-1200w-326ppi.png","max_value":25000,"min_value":500,"name":"Visa® Prepaid Card USD","type":"TANGO"}},"CashoutMethodResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout_method":{"$ref":"#/components/schemas/CashoutMethodOut"}},"type":"object","required":["status","cashout_method"],"title":"CashoutMethodResponse"},"CashoutMethodsResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout_methods":{"items":{"$ref":"#/components/schemas/CashoutMethodOut"},"type":"array","title":"Cashout Methods"}},"type":"object","required":["status","cashout_methods"],"title":"CashoutMethodsResponse"},"CashoutRequestInfo":{"properties":{"id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Id","description":"Unique ID for this cashout. This may be NULL if the status is REJECTED or FAILED, which may happen if the request is invalid.","examples":["3ceb847aaf9f40f4bd15b2b5e083abf6"]},"description":{"type":"string","title":"Description","description":"This is the name of the cashout method.","examples":["Visa® Prepaid Card USD"]},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"status":{"anyOf":[{"$ref":"#/components/schemas/PayoutStatus"},{"type":"null"}],"description":" - `PENDING` = PENDING\n - `APPROVED` = APPROVED\n - `REJECTED` = REJECTED\n - `CANCELLED` = CANCELLED\n - `FAILED` = FAILED\n - `COMPLETE` = COMPLETE","default":"PENDING","examples":["PENDING"]},"transaction_info":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Transaction Info"}},"type":"object","required":["id","description"],"title":"CashoutRequestInfo","description":"See models.thl.payout: PayoutEvent. We've confused a CashOut and a\nPayout. This is used only in the API response."},"CashoutRequestResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"cashout":{"$ref":"#/components/schemas/CashoutRequestInfo"}},"type":"object","required":["status","cashout"],"title":"CashoutRequestResponse"},"Category":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid","examples":["c109fbcaddac48cf88d5957c088ad446"]},"adwords_vertical_id":{"anyOf":[{"type":"string","maxLength":8},{"type":"null"}],"title":"Adwords Vertical Id"},"label":{"type":"string","maxLength":255,"title":"Label","examples":["Hair Loss"]},"path":{"type":"string","pattern":"^\\/.*[^\\/]$","title":"Path","examples":["/Beauty & Fitness/Hair Care/Hair Loss"]},"parent_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Parent Uuid","examples":["2a3e09d812ac41458c84def5b25e4364"]}},"type":"object","required":["uuid","label","path"],"title":"Category"},"CategoryAssociation":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"The category ID","examples":["c8642a1b86d9460cbe8f7e8ae6e56ee4"]},"label":{"type":"string","maxLength":255,"title":"Label","description":"The category label","examples":["People & Society"]},"adwords_id":{"anyOf":[{"type":"string","maxLength":8},{"type":"null"}],"title":"Adwords Id","examples":["14"]},"adwords_label":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Adwords Label","examples":["People & Society"]},"p":{"type":"number","maximum":1.0,"minimum":0.0,"title":"P","description":"The strength of the association of this bucketwith this category. Will sum to 1 within a bucket.","examples":[1.0]}},"type":"object","required":["id","label","p"],"title":"CategoryAssociation","description":"Used in an offerwall. Stores the association between a category\nand a bucket, with a score."},"ContestEndCondition":{"properties":{"target_entry_amount":{"anyOf":[{"anyOf":[{"type":"integer","minimum":0.0},{"type":"integer","exclusiveMinimum":0.0}],"ge":1},{"type":"null"}],"title":"Target Entry Amount","description":"The contest is over once this amount is reached. (sum of all entry amount)"},"ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ends At","description":"The contest is over at this time."}},"type":"object","title":"ContestEndCondition","description":"Defines the conditions to evaluate to determine when the contest\nis over. Multiple conditions can be set. The contest is over\nonce ANY conditions are met."},"ContestEndReason":{"type":"string","enum":["cancelled","target_entry_amount","ends_at","max_winners"],"title":"ContestEndReason","description":"Defines why a contest ended"},"ContestEntry":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"entry_type":{"$ref":"#/components/schemas/ContestEntryType"},"amount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"integer"}],"title":"Amount","description":"The amount of the entry in integer counts or USD Cents","gt":0},"amount_str":{"type":"string","title":"Amount Str","readOnly":true},"censored_product_user_id":{"type":"string","title":"Censored Product User Id","readOnly":true}},"type":"object","required":["entry_type","amount","amount_str","censored_product_user_id"],"title":"ContestEntry"},"ContestEntryRule":{"properties":{"max_entry_amount_per_user":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Entry Amount Per User","description":"Maximum total value of entries per user"},"max_daily_entries_per_user":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Daily Entries Per User","description":"Maximum entries per user allowed per day for this contest"},"min_completes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Completes"},"min_membership_level":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Membership Level"},"id_verified":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Id Verified"}},"type":"object","title":"ContestEntryRule","description":"Defines rules the user must meet to be allowed to enter this contest\nOnly applies if the ContestType is ENTRY!"},"ContestEntryTrigger":{"type":"string","enum":["task_complete","task_attempt","referral"],"title":"ContestEntryTrigger","description":"Defines what action/event triggers a (possible) entry into the contest (automatically).\nThis only is valid on milestone contests"},"ContestEntryType":{"type":"string","enum":["count","cash"],"title":"ContestEntryType","description":"All entries into a contest must be of the same type, and match\nthe entry_type of the Contest itself."},"ContestPrize":{"properties":{"kind":{"$ref":"#/components/schemas/ContestPrizeKind","description":"\nAllowed values: \n - __physical__ *(PHYSICAL)*: A physical prize (e.g. a iPhone, cash in the mail, dinner with Max)\n - __promotion__ *(PROMOTION)*: A promotion is a temporary or special offer that provides extra value or benefits (e.g. 20% bonus on completes for the next 7 days)\n - __cash__ *(CASH)*: Money is deposited into user's virtual wallet"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"estimated_cash_value":{"type":"integer","minimum":0.0,"title":"Estimated Cash Value","description":"Estimated cash value of prize in USDCents"},"cash_amount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Cash Amount","description":"If the kind=ContestPrizeKind.CASH, this is the amount of the prize"},"promotion_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Promotion Id","description":"If the kind=ContestPrizeKind.PROMOTION, this is the promotion ID"},"leaderboard_rank":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Leaderboard Rank","description":"The prize is for achieving this rank in the associated leaderboard. The highest rank is 1."}},"type":"object","required":["kind","estimated_cash_value"],"title":"ContestPrize"},"ContestPrizeKind":{"type":"string","enum":["physical","promotion","cash"],"title":"ContestPrizeKind"},"ContestStatus":{"type":"string","enum":["active","completed","cancelled"],"title":"ContestStatus"},"ContestWinner":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this user won this prize"},"prize":{"$ref":"#/components/schemas/ContestPrize"},"awarded_cash_amount":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Awarded Cash Amount","description":"The actual amount this user receives. For cash prizes, if there was a tie, this could be different from the prize amount."},"product_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product User Id","readOnly":true}},"type":"object","required":["prize","product_user_id"],"title":"ContestWinner","description":"In a Raffle, the ContestEntryType can be COUNT or CASH. In the CASH type,\nthe unit of entry is 1 USDCent (one penny). Implicitly, each penny entered\nbuys 1 entry into the raffle, and one entry is randomly selected for\neach prize.\n\nA contest should have as many winners as there are prizes\nspecial case 1: there are fewer entries than prizes\nspecial case 2: leaderboard contest with ties"},"CountStat":{"properties":{"facet":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"number"}]},"propertyNames":{"enum":["country_iso","day","month"]},"type":"object","title":"Facet","description":"The grouping criteria","examples":[{"country_iso":"us"}]},"count":{"type":"integer","title":"Count","description":"The count value for the given metric and facet"}},"type":"object","required":["facet","count"],"title":"CountStat"},"CreateCashMailCashoutMethodRequest":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"Bpuid","description":"(product_user_id) The user to create this cashout method for.","examples":["app-user-9329ebd"]},"type":{"type":"string","const":"CASH_IN_MAIL","title":"Type","default":"CASH_IN_MAIL"},"delivery_address":{"$ref":"#/components/schemas/USDeliveryAddress","description":"Delivery address where payment should be sent"}},"type":"object","required":["bpuid","delivery_address"],"title":"CreateCashMailCashoutMethodRequest"},"CreateCashoutRequest":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"Bpuid","description":"(product_user_id) The user requesting a cashout.","examples":["app-user-9329ebd"]},"amount":{"type":"integer","exclusiveMinimum":0.0,"title":"Amount","description":"(USD cents) The amount requested for the cashout.","examples":[531]},"cashout_method_id":{"type":"string","maxLength":32,"minLength":32,"title":"Cashout Method Id","description":"Unique ID for the cashout method the cashout is being requested with.","examples":["941d489c3ce04eb39a0ddb7f8f75db74"]}},"type":"object","required":["bpuid","amount","cashout_method_id"],"title":"CreateCashoutRequest"},"CreatePayPalCashoutMethodRequest":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"Bpuid","description":"(product_user_id) The user to create this cashout method for.","examples":["app-user-9329ebd"]},"type":{"type":"string","const":"PAYPAL","title":"Type","default":"PAYPAL"},"email":{"type":"string","format":"email","title":"Email","description":"Email address of the paypal user","examples":["test@example.com"]}},"type":"object","required":["bpuid","email"],"title":"CreatePayPalCashoutMethodRequest"},"Currency":{"type":"string","enum":["USD","CAD","GBP","EUR","INR","AUD","PLN","SEK","SGD","MXN"],"title":"Currency"},"DeliveryStatus":{"type":"string","enum":["Pending","Shipped","In Transit","Out for Delivery","Delivered","Returned","Canceled","Failed Attempt","Lost"],"title":"DeliveryStatus"},"Direction":{"type":"integer","enum":[-1,1],"title":"Direction","description":"Entries on the debit side will increase debit normal accounts, while\nentries on the credit side will decrease them. Conversely, entries on\nthe credit side will increase credit normal accounts, while entries on\nthe debit side will decrease them.\n\nBy convention (?), the db will store transactions as debit-normal. For\na credit-normal account, we should flip the signs."},"DurationSummary":{"properties":{"min":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Min"},"max":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Max"},"mean":{"anyOf":[{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Mean"},"q1":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Q1"},"q2":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Q2"},"q3":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Q3"},"lower_whisker":{"type":"integer","title":"Lower Whisker","readOnly":true},"upper_whisker":{"type":"integer","title":"Upper Whisker","readOnly":true}},"type":"object","required":["min","max","q1","q2","q3","lower_whisker","upper_whisker"],"title":"DurationSummary","description":"Durations are in integer seconds.\nDescribes the statistical distribution of expected durations of tasks within this bucket.","examples":[{"max":1180,"mean":660,"min":112,"q1":457,"q2":650,"q3":1103}]},"EventEnvelope":{"properties":{"event_uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Event Uuid"},"event_type":{"$ref":"#/components/schemas/EventType"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"version":{"type":"integer","title":"Version","default":1},"product_user_id":{"anyOf":[{"type":"string","maxLength":128,"minLength":3},{"type":"null"}],"title":"Product User Id","description":"A unique identifier for each user. This is hidden unlessthe event is for the requesting user.","examples":["app-user-9329ebd"]},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"payload":{"oneOf":[{"$ref":"#/components/schemas/TaskEnterPayload"},{"$ref":"#/components/schemas/TaskFinishPayload"},{"$ref":"#/components/schemas/SessionEnterPayload"},{"$ref":"#/components/schemas/SessionFinishPayload"}],"title":"Payload","discriminator":{"propertyName":"event_type","mapping":{"session.enter":"#/components/schemas/SessionEnterPayload","session.finish":"#/components/schemas/SessionFinishPayload","task.enter":"#/components/schemas/TaskEnterPayload","task.finish":"#/components/schemas/TaskFinishPayload"}}}},"type":"object","required":["event_type","product_id","payload"],"title":"EventEnvelope"},"EventMessage":{"properties":{"kind":{"type":"string","const":"event","title":"Kind","default":"event"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"data":{"$ref":"#/components/schemas/EventEnvelope"}},"type":"object","required":["data"],"title":"EventMessage"},"EventType":{"type":"string","enum":["task.enter","task.finish","session.enter","session.finish","wallet.credit","wallet.debit","user.created","user.active"],"title":"EventType"},"GeoIPInformation":{"properties":{"geoname_id":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Geoname Id"},"continent_code":{"anyOf":[{"type":"string","maxLength":2},{"type":"null"}],"title":"Continent Code"},"continent_name":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Continent Name"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso","description":"The ISO code of the country associated with the IP address.","examples":["bj"]},"country_name":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Country Name"},"subdivision_1_iso":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Subdivision 1 Iso","description":"The ISO code of the primary subdivision (e.g., state or province)."},"subdivision_1_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Subdivision 1 Name","description":"The name of the primary subdivision (e.g., state or province)."},"subdivision_2_iso":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Subdivision 2 Iso","description":"The ISO code of the secondary subdivision (if applicable)."},"subdivision_2_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Subdivision 2 Name","description":"The name of the secondary subdivision (if applicable)."},"city_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"City Name","description":"The name of the city associated with the IP address.","examples":["Jasonland"]},"metro_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Metro Code"},"time_zone":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Time Zone","description":"The time zone associated with the geographical location.","examples":["America/St_Lucia"]},"is_in_european_union":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is In European Union"},"updated":{"type":"string","format":"date-time","title":"Updated"},"ip":{"type":"string","title":"Ip"},"registered_country_iso":{"anyOf":[{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},{"type":"null"}],"title":"Registered Country Iso","description":"The ISO code of the country where the IP address is registered.","examples":["bd"]},"is_anonymous":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Anonymous","description":"Indicates whether the IP address is associated with an anonymous source (e.g., VPN, proxy).","examples":[false]},"is_anonymous_vpn":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Anonymous Vpn"},"is_hosting_provider":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Hosting Provider"},"is_public_proxy":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Public Proxy"},"is_tor_exit_node":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Tor Exit Node"},"is_residential_proxy":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Residential Proxy"},"autonomous_system_number":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Autonomous System Number"},"autonomous_system_organization":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Autonomous System Organization"},"domain":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Domain"},"isp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Isp","description":"The Internet Service Provider associated with the IP address.","examples":["Comcast"]},"mobile_country_code":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Mobile Country Code"},"mobile_network_code":{"anyOf":[{"type":"string","maxLength":3},{"type":"null"}],"title":"Mobile Network Code"},"network":{"anyOf":[{"type":"string","maxLength":56},{"type":"null"}],"title":"Network"},"organization":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Organization"},"static_ip_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Static Ip Score","description":"A score indicating the likelihood that the IP address is static."},"user_type":{"anyOf":[{"$ref":"#/components/schemas/AccessType"},{"type":"null"}],"description":"The type of user associated with the IP address (e.g., 'residential', 'business').","examples":["residential"]},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code","description":"The postal code associated with the IP address.","examples":["85242"]},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude","description":"The latitude coordinate of the IP address location.","examples":[-67.093362]},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude","description":"The longitude coordinate of the IP address location.","examples":[-66.51243]},"accuracy_radius":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Accuracy Radius","description":"The approximate radius of accuracy for the latitude and longitude, in kilometers.","examples":[73]}},"type":"object","required":["country_iso","ip"],"title":"GeoIPInformation"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IntegrationMode":{"type":"string","enum":["platform","pass_through"],"title":"IntegrationMode"},"Leaderboard":{"properties":{"id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Id","description":"Unique ID for this leaderboard","examples":["845b0074ad533df580ebb9c80cc3bce1"]},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Descriptive name for the leaderboard based on the board_code","examples":["Number of Completes"]},"board_code":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts","examples":["complete_count"]},"bpid":{"type":"string","maxLength":32,"minLength":32,"title":"Bpid","description":"product_id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"country_iso":{"type":"string","title":"Country Iso","description":"The country this leaderboard is for.","examples":["us"]},"freq":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00","examples":["daily"]},"timezone_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone Name","description":"The timezone for the requested country","examples":["America/New_York"]},"sort_order":{"type":"string","enum":["ascending","descending"],"title":"Sort Order","default":"descending"},"row_count":{"type":"integer","minimum":0.0,"title":"Row Count","description":"The total number of rows in the leaderboard.","examples":[2]},"rows":{"items":{"$ref":"#/components/schemas/LeaderboardRow"},"type":"array","title":"Rows","examples":[[{"bpuid":"app-user-9329ebd","rank":1,"value":4},{"bpuid":"app-user-7923skw","rank":2,"value":3}]]},"period_start_local":{"type":"string","format":"date-time","title":"Period Start Local","description":"The start of the time period covered by this board in local time, tz-aware","examples":["2024-07-12T00:00:00-04:00"]},"period_end_local":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period End Local","description":"The end of the time period covered by this board in local time, tz-aware","examples":["2024-07-12T23:59:59.999999-04:00"]},"start_timestamp":{"type":"integer","title":"Start Timestamp","description":"(unix timestamp) The start time of the time range this leaderboard covers.","readOnly":true,"examples":[1720756800]},"end_timestamp":{"type":"integer","title":"End Timestamp","description":"(unix timestamp) The end time of the time range this leaderboard covers.","readOnly":true,"examples":[1720843199]},"utc_offset":{"type":"string","title":"Utc Offset","description":"The UTC offset for the timezone","readOnly":true,"examples":["-0400"]},"local_start_time":{"type":"string","title":"Local Start Time","description":"The start time of the time range this leaderboard covers (local time, in the leaderboard's timezone).","readOnly":true,"examples":["2024-07-12T00:00:00-04:00"]},"local_end_time":{"type":"string","title":"Local End Time","description":"The end time of the time range this leaderboard covers (local time, in the leaderboard's timezone).","readOnly":true,"examples":["2024-07-12T23:59:59.999999-04:00"]},"start_end_str":{"type":"string","title":"Start End Str","description":"A formatted string for time period covered by this leaderboard. Can be used to display to users.","readOnly":true,"examples":["2024-02-07 to 2024-02-08"]}},"type":"object","required":["board_code","bpid","country_iso","freq","row_count","period_start_local","start_timestamp","end_timestamp","utc_offset","local_start_time","local_end_time","start_end_str"],"title":"Leaderboard","description":"A leaderboard exists independently for each product_id in each country.\nEach country is associated with a single timezone. There is a daily,\nweekly, and monthly leaderboard."},"LeaderboardCode":{"type":"string","enum":["complete_count","largest_user_payout","sum_user_payout"],"title":"LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent."},"LeaderboardContestUserView":{"properties":{"name":{"type":"string","maxLength":128,"title":"Name","description":"Name of contest. Can be displayed to user."},"description":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Description","description":"Description of contest. Can be displayed to user."},"contest_type":{"type":"string","const":"leaderboard","title":"Contest Type","default":"leaderboard"},"end_condition":{"$ref":"#/components/schemas/ContestEndCondition"},"prizes":{"items":{"$ref":"#/components/schemas/ContestPrize"},"type":"array","minItems":1,"title":"Prizes"},"starts_at":{"type":"string","format":"date-time","title":"Starts At","description":"When the contest starts"},"terms_and_conditions":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Terms And Conditions"},"status":{"$ref":"#/components/schemas/ContestStatus","default":"active"},"country_isos":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Isos","description":"Contest is restricted to these countries. If null, all countries are allowed"},"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"Contest applies only to a single BP"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this contest was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When this contest was last modified. Does not include entries being created/modified"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the contest ended"},"end_reason":{"anyOf":[{"$ref":"#/components/schemas/ContestEndReason"},{"type":"null"}],"description":"The reason the contest ended"},"product_user_id":{"type":"string","title":"Product User Id"},"user_winnings":{"items":{"$ref":"#/components/schemas/ContestWinner"},"type":"array","title":"User Winnings","description":"The prizes won in this contest by the requested user"},"leaderboard_key":{"type":"string","title":"Leaderboard Key","description":"The specific leaderboard instance this contest is connected to","examples":["leaderboard:7a9d8d02334449ceb105764f77e1ba97:us:weekly:2025-05-26:complete_count"]},"tie_break_strategy":{"type":"string","const":"split_prize_pool","title":"Tie Break Strategy","default":"split_prize_pool"},"country_iso":{"type":"string","title":"Country Iso","readOnly":true},"user_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Rank","description":"The current rank of this user in this contest","readOnly":true}},"additionalProperties":false,"type":"object","required":["name","product_id","product_user_id","leaderboard_key","country_iso","user_rank"],"title":"LeaderboardContestUserView"},"LeaderboardFrequency":{"type":"string","enum":["daily","weekly","monthly"],"title":"LeaderboardFrequency","description":"The time period range for the leaderboard."},"LeaderboardResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"leaderboard":{"$ref":"#/components/schemas/Leaderboard"}},"type":"object","required":["status","leaderboard"],"title":"LeaderboardResponse"},"LeaderboardRow":{"properties":{"bpuid":{"type":"string","title":"Bpuid","description":"product_user_id","examples":["app-user-9329ebd"]},"rank":{"type":"integer","title":"Rank","description":"The numerical data ranks (1 through n) of the values. Ties are ranked using the lowest rank in the group.","examples":[1]},"value":{"type":"integer","title":"Value","description":"The value. The meaning of the value is dependent on the LeaderboardCode.","examples":[7]},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name","description":"Optional public name chosen by the user"}},"type":"object","required":["bpuid","rank","value"],"title":"LeaderboardRow"},"LeaderboardWinner":{"properties":{"rank":{"type":"integer","title":"Rank","description":"The user's final rank in the leaderboard","examples":[1]},"freq":{"$ref":"#/components/schemas/LeaderboardFrequency","description":"The time period range for the leaderboard.\n\nAllowed values: \n - __daily__ *(DAILY)*: UTC midnight to UTC midnight\n - __weekly__ *(WEEKLY)*: Sunday Midnight to Sunday Midnight UTC\n - __monthly__ *(MONTHLY)*: Jan 1 00:00:00","examples":["daily"]},"board_code":{"$ref":"#/components/schemas/LeaderboardCode","description":"The type of leaderboard. What the \"values\" represent.\n\nAllowed values: \n - __complete_count__ *(COMPLETE_COUNT)*: Number of Completes\n - __largest_user_payout__ *(LARGEST_PAYOUT)*: Largest Single Payout\n - __sum_user_payout__ *(SUM_PAYOUTS)*: (Sum of) Total Payouts","examples":["complete_count"]},"country_iso":{"type":"string","title":"Country Iso","description":"The country this leaderboard is for.","examples":["us"]},"issued":{"type":"string","format":"date-time","title":"Issued","description":"When the prize was issued.","examples":["2022-10-17T05:59:14.570231Z"]},"bpuid":{"type":"string","title":"Bpuid","description":"product_user_id","examples":["app-user-9329ebd"]},"description":{"type":"string","title":"Description","examples":["Bonus for daily contest"]},"amount":{"type":"integer","title":"Amount","description":"(USD cents) The reward amount","examples":[1000]},"amount_str":{"type":"string","title":"Amount Str","description":"The amount as a formatted string in USD. Can be displayed to the user.","examples":["$10.00"]},"contest_start":{"type":"string","format":"date-time","title":"Contest Start","description":"When the leaderboard started","examples":["2022-10-16T04:00:00Z"]},"contest_end":{"type":"string","format":"date-time","title":"Contest End","description":"When the leaderboard ended","examples":["2022-10-17T04:00:00Z"]}},"type":"object","required":["rank","freq","board_code","country_iso","issued","bpuid","description","amount","amount_str","contest_start","contest_end"],"title":"LeaderboardWinner"},"LeaderboardWinnerResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"winners":{"items":{"$ref":"#/components/schemas/LeaderboardWinner"},"type":"array","title":"Winners"}},"type":"object","required":["status"],"title":"LeaderboardWinnerResponse"},"LedgerAccount":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid","description":"A unique identifier for this Ledger Account","examples":["c3c3566b5b1b4961b63a5670a2dc923d"]},"display_name":{"type":"string","maxLength":64,"title":"Display Name","description":"Human-readable description of the Ledger Account","examples":["BP Wallet c3c3566b5b1b4961b63a5670a2dc923d"]},"qualified_name":{"type":"string","maxLength":255,"title":"Qualified Name"},"account_type":{"$ref":"#/components/schemas/AccountType","description":" - `bp_commission` = BP_COMMISSION\n - `bp_wallet` = BP_WALLET\n - `user_wallet` = USER_WALLET\n - `user_attempt_credit` = USER_ATTEMPT_CREDIT\n - `cash` = CASH\n - `revenue` = REVENUE\n - `expense` = EXPENSE\n - `contest_wallet` = CONTEST_WALLET\n - `credit_line` = CREDIT_LINE\n - `wa_wallet` = WA_WALLET\n - `wa_budget_pool` = WA_BUDGET_POOL\n - `wa_held` = WA_HELD\n - `wa_credit_line` = WA_CREDIT_LINE","examples":["bp_wallet"]},"normal_balance":{"$ref":"#/components/schemas/Direction","description":" - `-1` = CREDIT\n - `1` = DEBIT"},"reference_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Type"},"reference_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Reference Uuid","description":"The associated Product ID or other parent account thatthis Ledger Account is intended to track transactions for.If Wallet mode is enabled, this can also handle trackingindividual users.","examples":["61dd0b086fd048518762757612b4a6d3"]},"currency":{"type":"string","maxLength":32,"title":"Currency","description":"GRL's Ledger system allows tracking of transactions inany currency possible. This is useful for trackingpoints, stars, coins, or any other currency that may beused in a Supplier's platform.","default":"USD"}},"type":"object","required":["display_name","qualified_name","account_type","normal_balance"],"title":"LedgerAccount"},"LedgerEntry":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Id"},"direction":{"$ref":"#/components/schemas/Direction"},"account_uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Account Uuid"},"amount":{"type":"integer","exclusiveMaximum":9.223372036854776e+18,"exclusiveMinimum":0.0,"title":"Amount","description":"The USDCent amount. A LedgerEntry cannot be made for0 USDCent and it cannot be negative.","examples":[531]},"transaction_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Transaction Id"}},"type":"object","required":["direction","account_uuid","amount"],"title":"LedgerEntry"},"LedgerTransaction":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Id"},"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction (TX) was created into the database.This does not represent the exact time for any actionwhich may be responsible for this Transaction (TX), and TX timestamps will likely be a few milliseconds delayed"},"ext_description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Ext Description"},"tag":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Tag"},"metadata":{"additionalProperties":{"type":"string"},"type":"object","title":"Metadata"},"entries":{"items":{"$ref":"#/components/schemas/LedgerEntry"},"type":"array","title":"Entries","description":"A Transaction (TX) is composed of multiple Entry events."}},"additionalProperties":false,"type":"object","title":"LedgerTransaction"},"ManageCashoutBody":{"properties":{"payout_id":{"type":"string","maxLength":32,"minLength":32,"title":"Payout Id"},"new_status":{"$ref":"#/components/schemas/PayoutStatus"}},"type":"object","required":["payout_id","new_status"],"title":"ManageCashoutBody"},"MarketProfileKnowledge":{"properties":{"source":{"$ref":"#/components/schemas/Source","maxLength":16,"description":"Marketplace this question is from"},"question_id":{"type":"string","title":"Question Id","examples":["gender","1843","gender_plus"]},"answer":{"items":{"type":"string"},"type":"array","title":"Answer","examples":[["male"],["7657644"],["1"]]},"created":{"type":"string","format":"date-time","title":"Created","description":"When the User submitted this Profiling data"}},"type":"object","required":["source","question_id","created"],"title":"MarketProfileKnowledge","description":"This is used solely in API responses, so it is simplified."},"MarketplaceBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"x":{"type":"integer","minimum":0.0,"title":"X","description":"For UI. Provides a dimensionality position for the bucket on the x-axis.","default":0,"examples":[0,1,2]},"y":{"type":"integer","minimum":0.0,"title":"Y","description":"For UI. Provides a dimensionality position for the bucket on the y-axis.","default":0,"examples":[0,1,2]},"name":{"type":"string","title":"Name","description":"Currently unused. Will always return empty string","default":""},"description":{"type":"string","title":"Description","description":"Currently unused. Will always return empty string","default":""},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"duration":{"$ref":"#/components/schemas/DurationSummary"},"payout":{"$ref":"#/components/schemas/PayoutSummary"},"source":{"type":"string","enum":["innovate","dynata","schlesinger","purespectrum","morning","pollfish","precision","repdata","prodege"],"title":"Source","description":"this is the source of the contents","examples":["pollfish"]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","duration","payout","source"],"title":"MarketplaceBucket"},"MarketplaceInventorySummary":{"properties":{"live_tasks":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Live Tasks","description":"The count of tasks that are currently live"},"live_gen_pop_tasks":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Live Gen Pop Tasks","description":"The count of gen-pop tasks that are currently live"},"tasks_created":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Tasks Created","description":"The count of tasks created"},"required_finishes":{"items":{"$ref":"#/components/schemas/CountStat"},"type":"array","title":"Required Finishes","description":"Number of finishes needed across all live tasks"},"payout":{"items":{"$ref":"#/components/schemas/StatisticalSummaryStat"},"type":"array","title":"Payout","description":"The distribution of payouts for all live tasks"},"expected_duration":{"items":{"$ref":"#/components/schemas/StatisticalSummaryStat"},"type":"array","title":"Expected Duration","description":"The distribution of expected durations for all live tasks"},"required_finishes_per_task":{"items":{"$ref":"#/components/schemas/StatisticalSummaryStat"},"type":"array","title":"Required Finishes Per Task","description":"The distribution of required finishes on all live tasks"}},"type":"object","title":"MarketplaceInventorySummary"},"MarketplaceOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/MarketplaceBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"MarketplaceOfferwall","description":"Returns buckets grouped by marketplace, one per marketplace, with the\ntasks ordered by quality.\n\nOfferwall code: `5fa23085`"},"MarketplaceOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/MarketplaceOfferwall"}},"type":"object","required":["info","offerwall"],"title":"MarketplaceOfferwallResponse"},"MarketplaceSummary":{"properties":{"inventory":{"$ref":"#/components/schemas/MarketplaceInventorySummary","description":"Inventory of the marketplace"},"user_activity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Activity","description":"User activity of the marketplace"}},"type":"object","required":["inventory"],"title":"MarketplaceSummary"},"MaxGaugeBySource":{"properties":{"value":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Value"},"by_source":{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object","title":"By Source"}},"type":"object","title":"MaxGaugeBySource"},"MilestoneContestEndCondition":{"properties":{"max_winners":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Winners","description":"The contest will end once this many users have won (i.e. reachedthe milestone)."},"ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ends At","description":"The Contest is over at the ends_at time."}},"type":"object","title":"MilestoneContestEndCondition","description":"Defines the conditions to evaluate to determine when the contest is over.\nMultiple conditions can be set. The contest is over once ANY conditions are met."},"MilestoneUserView":{"properties":{"target_amount":{"type":"integer","exclusiveMinimum":0.0,"title":"Target Amount","description":"Each user 'wins' (receives prizes) once this target amount is reached."},"entry_trigger":{"anyOf":[{"$ref":"#/components/schemas/ContestEntryTrigger"},{"type":"null"}],"description":"What user action triggers an entry automatically."},"valid_for":{"anyOf":[{"type":"string","format":"duration"},{"type":"null"}],"title":"Valid For","description":"The time after valid_for_event for which the contest is open"},"valid_for_event":{"anyOf":[{"type":"string","const":"signup"},{"type":"null"}],"title":"Valid For Event"},"name":{"type":"string","maxLength":128,"title":"Name","description":"Name of contest. Can be displayed to user."},"description":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Description","description":"Description of contest. Can be displayed to user."},"contest_type":{"type":"string","const":"milestone","title":"Contest Type","default":"milestone"},"end_condition":{"$ref":"#/components/schemas/MilestoneContestEndCondition"},"prizes":{"items":{"$ref":"#/components/schemas/ContestPrize"},"type":"array","minItems":1,"title":"Prizes"},"starts_at":{"type":"string","format":"date-time","title":"Starts At","description":"When the contest starts"},"terms_and_conditions":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Terms And Conditions"},"status":{"$ref":"#/components/schemas/ContestStatus","default":"active"},"country_isos":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Isos","description":"Contest is restricted to these countries. If null, all countries are allowed"},"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"Contest applies only to a single BP"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this contest was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When this contest was last modified. Does not include entries being created/modified"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the contest ended"},"end_reason":{"anyOf":[{"$ref":"#/components/schemas/ContestEndReason"},{"type":"null"}],"description":"The reason the contest ended"},"product_user_id":{"type":"string","title":"Product User Id"},"user_winnings":{"items":{"$ref":"#/components/schemas/ContestWinner"},"type":"array","title":"User Winnings","description":"The prizes won in this contest by the requested user"},"entry_type":{"type":"string","const":"count","title":"Entry Type","default":"count"},"win_count":{"type":"integer","title":"Win Count","description":"The number of times the milestone has been reached.","default":0},"user_amount":{"type":"integer","title":"User Amount","description":"The total amount for this user for this contest"}},"additionalProperties":false,"type":"object","required":["target_amount","name","end_condition","product_id","product_user_id","user_amount"],"title":"MilestoneUserView"},"OfferWallCategoryRequest":{"properties":{"adwords_category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Adwords Category","examples":[["45","65"]]},"category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Category","examples":[["98c137e4e90a4d92ac6c00e523eb1b50"]]},"exclude_adwords_category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exclude Adwords Category","examples":[["1558"]]},"exclude_category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exclude Category","examples":[["21536f160f784189be6194ca894f3a65","7aa8bf4e71a84dc3b2035f93f9f9c77e"]]}},"type":"object","title":"OfferWallCategoryRequest"},"OfferWallInfo":{"properties":{"success":{"type":"boolean","title":"Success"}},"type":"object","required":["success"],"title":"OfferWallInfo"},"OfferWallRequestYieldmanParams":{"properties":{"conversion_factor_adj":{"type":"number","title":"Conversion Factor Adj","description":"Centered around 0. Higher results in higher weight given to conversion (in the scoring function)","default":0.0},"dropoffrate_factor_adj":{"type":"number","title":"Dropoffrate Factor Adj","description":"Centered around 0. Higher results in higher penalty given to dropoffs (in the scoring function)","default":0.0},"longfail_factor_adj":{"type":"number","title":"Longfail Factor Adj","description":"Centered around 0. Higher results in higher penalty given to long fail (in the scoring function)","default":0.0},"recon_factor_adj":{"type":"number","title":"Recon Factor Adj","description":"Centered around 0. Higher results in higher penalty given to recons (in the scoring function)","default":0.0},"recon_likelihood_max":{"type":"number","title":"Recon Likelihood Max","description":"Tolerance for recon likelihood (0 to 1)","default":0.8}},"type":"object","title":"OfferWallRequestYieldmanParams"},"OfferwallConfig":{"properties":{},"type":"object","title":"OfferwallConfig"},"OfferwallReason":{"type":"string","enum":["USER_BLOCKED","HIGH_RECON_RATE","UNCOMMON_DEMOGRAPHICS","UNDER_MINIMUM_AGE","EXHAUSTED_HIGH_VALUE_SUPPLY","ALL_ELIGIBLE_ATTEMPTED","LOW_CURRENT_SUPPLY"],"title":"OfferwallReason"},"OneShotOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/OneShotOfferwallBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"OneShotOfferwall","description":"Each bucket has only 1 single task, and only basic info is returned\n about each bucket.\n\nOfferwall code: `6f27b1ae`"},"OneShotOfferwallBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"duration":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Duration","description":"The bucket's expected duration, in seconds"},"min_payout":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Min Payout","description":"The bucket's min payout, in usd cents"}},"additionalProperties":false,"type":"object","required":["id","uri","duration","min_payout"],"title":"OneShotOfferwallBucket"},"OneShotOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/OneShotOfferwall"}},"type":"object","required":["info","offerwall"],"title":"OneShotOfferwallResponse"},"POPFinancial":{"properties":{"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["acdb85c0874547659084ac88049e1bb1"]},"time":{"type":"string","format":"date-time","title":"Time","description":"The starting time block for the respective 'Period' thatthis grouping is on. The `time` could be the start of a 1 minute or 1 hour block for example."},"payout":{"type":"integer","minimum":0.0,"title":"Payout","description":"The total amount (in USD cents) that the Brokerage Producthas earned within a respective time period.","default":0,"examples":[59050]},"adjustment":{"type":"integer","title":"Adjustment","description":"The total amount (in USD cents) that the Brokerage Producthas had adjusted within a respective time period. Most ofthe time, this will be negative due to Complete to Incomplete reconciliations. However, it can also be positive due to Incomplete to Complete adjustments.","examples":[464]},"adjustment_types":{"items":{"$ref":"#/components/schemas/AdjustmentType"},"type":"array","title":"Adjustment Types"},"expense":{"type":"integer","title":"Expense","description":"For Product accounts that are setup with Respondent payouts,competitions, user bonuses, or other associated 'costs', thoseexpenses are accounted for here. This will be negative forthose types of costs."},"net":{"type":"integer","title":"Net","description":"This is the sum of the Payout total, Adjustment and any Expenses total. It can be positive or negative for any specific time period.","examples":[59514]},"payment":{"type":"integer","title":"Payment","description":"Any ACH or Wire amount that was issued between GRL and the Supplier.","examples":[3408288]}},"type":"object","required":["time","adjustment","adjustment_types","expense","net","payment"],"title":"POPFinancial","description":"We can't use our USDCent class in here because aside from it not\n supporting negative values for our adjustments, FastAPI also\n complains because it doesn't know how to generate documentation\n for it. - Max 2024-06-25"},"PatternValidation":{"properties":{"message":{"type":"string","title":"Message","description":"Message to display if validation fails"},"pattern":{"type":"string","title":"Pattern","description":"Regex string to validate. min_length and max_length are checked separately, even if they are part of the regex."}},"type":"object","required":["message","pattern"],"title":"PatternValidation"},"PayoutConfig":{"properties":{"payout_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]},"payout_transformation":{"anyOf":[{"$ref":"#/components/schemas/PayoutTransformation"},{"type":"null"}],"description":"How the BP's payout is converted to the User's payout"}},"type":"object","title":"PayoutConfig","description":"Store configuration related to payouts, payout transformation, and user\npayout formatting."},"PayoutStatus":{"type":"string","enum":["PENDING","APPROVED","REJECTED","CANCELLED","FAILED","COMPLETE"],"title":"PayoutStatus","description":"The max size of the db field that holds this value is 20, so please\ndon't add new values longer than that!"},"PayoutSummary":{"properties":{"min":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Min"},"max":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Max"},"mean":{"anyOf":[{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Mean"},"q1":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Q1"},"q2":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Q2"},"q3":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Q3"},"lower_whisker":{"type":"integer","title":"Lower Whisker","readOnly":true},"upper_whisker":{"type":"integer","title":"Upper Whisker","readOnly":true}},"type":"object","required":["min","max","q1","q2","q3","lower_whisker","upper_whisker"],"title":"PayoutSummary","description":"Payouts are in Integer USD Cents","examples":[{"max":132,"min":14,"q1":45,"q2":68,"q3":124}]},"PayoutTransformation":{"properties":{"f":{"type":"string","enum":["payout_transformation_percent","payout_transformation_amt"],"title":"F","description":"The name of the transformation function to use."},"kwargs":{"anyOf":[{"$ref":"#/components/schemas/PayoutTransformationPercentArgs"},{"type":"null"}],"description":"The kwargs to pass to the transformation function.","examples":[{"max_payout":"5.00","pct":0.5}]}},"type":"object","required":["f"],"title":"PayoutTransformation","description":"This model describe how the bp_payout is converted to the user_payout.\nIf None, the user_payout is None.\n\nIf the user_wallet_enabled is `False`, the user_payout is used to\n 1) know how to transform the expected payouts for offerwall buckets\n (if min_payout is requested, this is based on the user_payout)\n 2) show the user (using the payout_format) how much they made (in\n the Task Status Response).\n\nIf the user_wallet_enabled is `True`, then in addition to the above, the\n user_payout is the amount actually paid to the user's wallet."},"PayoutTransformationPercentArgs":{"properties":{"pct":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Pct","description":"The percentage of the bp_payout to pay the user","examples":[0.5]},"min_payout":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Min Payout","description":"The minimum amount paid for a complete. Note: This does not check that the actual payout was at least this amount.","examples":["0.50"]},"max_payout":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Max Payout","description":"The maximum amount paid for a complete","examples":["5.00"]}},"type":"object","required":["pct"],"title":"PayoutTransformationPercentArgs"},"PayoutType":{"type":"string","enum":["PAYPAL","TANGO","DWOLLA","ACH","WIRE","CASH_IN_MAIL","PRIZE","AMT","AMT_BONUS","AMT_ASSIGNMENT","AMT_ASSIGNMENT"],"title":"PayoutType","description":"The method in which the requested payout is delivered."},"PaypalCashoutMethodData":{"properties":{"type":{"type":"string","const":"PAYPAL","title":"Type","default":"PAYPAL"},"email":{"type":"string","format":"email","title":"Email","description":"Email address of the paypal user","examples":["test@example.com"]}},"type":"object","required":["email"],"title":"PaypalCashoutMethodData"},"PingMessage":{"properties":{"kind":{"type":"string","const":"ping","title":"Kind","default":"ping"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","title":"PingMessage"},"PongMessage":{"properties":{"kind":{"type":"string","const":"pong","title":"Kind","default":"pong"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","title":"PongMessage"},"Product":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier of the Brokerage Product","examples":["1108d053e4fa47c5b0dbdcd03a7981e7"]},"name":{"type":"string","maxLength":255,"minLength":3,"title":"Name","description":"Name of the Brokerage Product. Must be unique within a Team","examples":["Website ABC"]},"enabled":{"type":"boolean","title":"Enabled","description":"This is only used to hard block a Product in order to immediately & safely protect against fraud entrances.","default":true},"payments_enabled":{"type":"boolean","title":"Payments Enabled","description":"This is only to determine if ACH or Wire payments should be made to the Product.","default":true},"created":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created","description":"When the Product was created, this does necessarily mean it started to retrieve traffic at that time."},"team_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Team Id","description":"The organization (group of generalresearch.com admin accounts) that is allowed to modify and manage thisProduct","examples":["b96c1209cf4a4baaa27d38082421a039"]},"business_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Business Id","description":"The legal business entity or individual that is responsible for this account, and that receive SupplierPayments for this Product's activity.","examples":["26bac7a8244b4c0da0c31384e3789fe3"]},"tags":{"items":{"$ref":"#/components/schemas/SupplierTag"},"type":"array","uniqueItems":true,"title":"Tags","description":"Tags which are used to annotate supplier traffic"},"commission_pct":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*(?:\\d{0,1}|(?=[\\d.]{1,7}0*$)\\d{0,1}\\.\\d{0,5}0*$)","title":"Commission Pct","default":"0.05"},"redirect_url":{"type":"string","title":"Redirect Url","description":"Where to redirect the user after finishing a session. When a user get redirected back to the supplier, a query param will be added with the name 'tsid', and the value of the TSID for the session. For example: callback_uri: 'https://www.example.com/test/?a=1&b=2' might result in the user getting redirected to: 'https://www.example.com/grl-callback/?a=1&b=2&tsid=c6ab6ba1e75b44e2bf5aab00fc68e3b7'.","examples":["https://www.example.com/grl-callback/?a=1&b=2"]},"harmonizer_domain":{"type":"string","title":"Harmonizer Domain","description":"This is the domain that is used for the GRS (General Research Survey) platform. This is a simple javascript application which may profile the respondent for anyprofiling questions, along with collecting any browserbased security information. The value is a scheme+domain only (no path).","default":"https://profile.generalresearch.com/"},"sources_config":{"anyOf":[{"$ref":"#/components/schemas/SourcesConfig"},{"$ref":"#/components/schemas/SupplyConfig"}],"title":"Sources Config"},"session_config":{"$ref":"#/components/schemas/SessionConfig"},"payout_config":{"$ref":"#/components/schemas/PayoutConfig"},"user_wallet_config":{"$ref":"#/components/schemas/UserWalletConfig"},"user_create_config":{"$ref":"#/components/schemas/UserCreateConfig"},"offerwall_config":{"$ref":"#/components/schemas/OfferwallConfig"},"profiling_config":{"$ref":"#/components/schemas/ProfilingConfig"},"user_health_config":{"$ref":"#/components/schemas/UserHealthConfig"},"yield_man_config":{"$ref":"#/components/schemas/YieldManConfig"},"balance":{"anyOf":[{"$ref":"#/components/schemas/ProductBalances"},{"type":"null"}],"description":"Product Balance"},"payouts_total_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payouts Total Str"},"payouts_total":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Payouts Total"},"payouts":{"anyOf":[{"items":{"$ref":"#/components/schemas/BrokerageProductPayoutEvent"},"type":"array"},{"type":"null"}],"title":"Payouts","description":"Product Payouts. These are the ACH or Wire payments that were sent to theBusiness on behalf of this specific Product"},"pop_financial":{"anyOf":[{"items":{"$ref":"#/components/schemas/POPFinancial"},"type":"array"},{"type":"null"}],"title":"Pop Financial"},"bp_account":{"anyOf":[{"$ref":"#/components/schemas/LedgerAccount"},{"type":"null"}]},"user_wallet":{"$ref":"#/components/schemas/UserWalletConfig","readOnly":true}},"type":"object","required":["name","redirect_url","user_wallet"],"title":"Product"},"ProductBalances":{"properties":{"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["7e94ebe63bbc4509876c4914cc61a984"]},"last_event":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Event"},"bp_payment_credit":{"type":"integer","minimum":0.0,"title":"Bp Payment Credit","description":"The total amount that has been earned by the Task completes, for this Brokerage Product account.","default":0,"examples":[18837]},"adjustment_credit":{"type":"integer","minimum":0.0,"title":"Adjustment Credit","description":"Positive reconciliations issued back to the Brokerage Product account.","default":0,"examples":[2]},"adjustment_debit":{"type":"integer","minimum":0.0,"title":"Adjustment Debit","description":"Negative reconciliations for any Task completes","default":0,"examples":[753]},"supplier_credit":{"type":"integer","minimum":0.0,"title":"Supplier Credit","description":"ACH or Wire amounts issued to GRL from a Supplier to recoup for a negative Brokerage Product balance","default":0,"examples":[0]},"supplier_debit":{"type":"integer","minimum":0.0,"title":"Supplier Debit","description":"ACH or Wire amounts sent to a Supplier","default":0,"examples":[10000]},"user_bonus_credit":{"type":"integer","minimum":0.0,"title":"User Bonus Credit","description":"If a respondent ever pays back an product account.","default":0,"examples":[0]},"user_bonus_debit":{"type":"integer","minimum":0.0,"title":"User Bonus Debit","description":"Pay a user into their wallet balance. There is no fee here. There is only a fee when the user requests a payout.The bonus could be as a bribe, winnings for a contest, leaderboard, etc.","default":0,"examples":[2745]},"issued_payment":{"type":"integer","minimum":0.0,"title":"Issued Payment","description":"This is the amount that we decide to credit as havingtaken from this Product. If there is any amount not issuedit is summed up over the Business to offset any negativebalances elsewhere.","default":0},"payout":{"type":"integer","title":"Task Payouts","description":"The sum amount of all Task payouts","readOnly":true,"examples":[18837]},"payout_usd_str":{"type":"string","title":"Task Payouts USD Str","readOnly":true,"examples":["$18,837.00"]},"adjustment":{"type":"integer","title":"Task Adjustments","description":"The sum amount of all Task Adjustments","readOnly":true,"examples":[-751]},"expense":{"type":"integer","title":"Product Expenses","description":"The sum amount of any associated Product Expenses (eg: user bonuses)","readOnly":true,"examples":[-2745]},"net":{"type":"integer","title":"Net Earnings","description":"The Product's Net Earnings which is equal to the totalamount of Task Payouts, with Task Adjustments and anyProduct Expenses deducted. This can be positive ornegative.","readOnly":true,"examples":[15341]},"payment":{"type":"integer","minimum":0.0,"title":"Supplier Payments","description":"The sum amount of all Supplier Payments (eg ACH or Wire transfers)","readOnly":true,"examples":[10000]},"payment_usd_str":{"type":"string","title":"Supplier Payments","readOnly":true,"examples":["$10,000"]},"balance":{"type":"integer","title":"Product Balance","description":"The Product's Balance which is equal to the Product's Netamount with already issued Supplier Payments deducted. This can be positive or negative.","readOnly":true,"examples":[5341]},"retainer":{"type":"integer","minimum":0.0,"title":"Smart Retainer","description":"The Smart Retainer is an about of money that is held byGRL to account for any Task Adjustments that may occurin the future. The amount will always be positive, andif the Product's balance is negative, the retainer will be $0.00 as the Product is not eligible for any SupplierPayments either way.","readOnly":true,"examples":[1335]},"retainer_usd_str":{"type":"string","title":"Smart Retainer USD Str","readOnly":true,"examples":["$1,335.00"]},"available_balance":{"type":"integer","minimum":0.0,"title":"Available Balance","description":"The Available Balance is the amount that is currently, andimmediately available for withdraw from the Supplier'sbalance. Supplier Payments are made every Friday for Businesses with an ACH connected Bank Account to GRL, while a Business that requires an International Wire are issued on the last Friday of every Month.","readOnly":true,"examples":[4006]},"available_balance_usd_str":{"type":"string","title":"Available Balance USD Str","readOnly":true,"examples":["$4,006.00"]},"recoup":{"type":"integer","minimum":0.0,"title":"Recoup","description":"The amount that must be held back to recover a negative Product balance. This is $0.00 when the Product balance is positive or zero; otherwise it is the absolute value of the negative balance. Business-level payout calculations use this amount to offset deficits from one Product against available funds from other Products before issuing Supplier Payments.","readOnly":true,"examples":[282]},"recoup_usd_str":{"type":"string","title":"Recoup Str","readOnly":true,"examples":["$2.04"]},"adjustment_percent":{"type":"number","title":"Adjustment Percentage","description":"The percentage of USDCent value that has been adjustedover all time for this Product.","readOnly":true,"examples":[0.064938]}},"type":"object","required":["payout","payout_usd_str","adjustment","expense","net","payment","payment_usd_str","balance","retainer","retainer_usd_str","available_balance","available_balance_usd_str","recoup","recoup_usd_str","adjustment_percent"],"title":"ProductBalances"},"ProfilingConfig":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"If False, the harmonizer/profiling system is not used at all. This should never be False unless special circumstances","default":true},"grs_enabled":{"type":"boolean","title":"Grs Enabled","description":"If grs_enabled is False, and is_grs is passed in the \n profiling-questions call, then don't actually return any questions. \n This allows a client to hit the endpoint with no limit and still get \n questions. In effect, this means that we'll redirect the user through \n the GRS system but won't present them any questions.","default":true},"n_questions":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"N Questions","description":"Use to hard code the number of questions to ask. None means use default algorithm."},"max_questions":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Questions","description":"The max number of questions we would ask in a session","default":10},"avg_question_count":{"type":"number","exclusiveMinimum":0.0,"title":"Avg Question Count","description":"The average number of questions to ask in a session","default":5},"task_injection_freq_mult":{"type":"number","exclusiveMinimum":0.0,"title":"Task Injection Freq Mult","description":"Scale how frequently we inject profiling questions, \n relative to the default. 1 is default, 2 is twice as often. 10 means \n always. 0.5 half as often","default":1},"non_us_mult":{"type":"number","exclusiveMinimum":0.0,"title":"Non Us Mult","description":"Non-us multiplier, used to increase freq and length of \n profilers in all non-us countries. This value is multiplied by \n task_injection_freq_mult and avg_question_count.","default":2},"hidden_questions_expiration_hours":{"type":"integer","exclusiveMinimum":0.0,"title":"Hidden Questions Expiration Hours","description":"How frequently we should refresh hidden questions","default":168}},"type":"object","title":"ProfilingConfig"},"ProfilingInfoResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"profiling-info":{"items":{"$ref":"#/components/schemas/UpkProperty"},"type":"array","title":"Profiling-Info"}},"type":"object","required":["status","profiling-info"],"title":"ProfilingInfoResponse"},"PropertyType":{"type":"string","enum":["i","n","x"],"title":"PropertyType"},"RaffleUserView":{"properties":{"name":{"type":"string","maxLength":128,"title":"Name","description":"Name of contest. Can be displayed to user."},"description":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Description","description":"Description of contest. Can be displayed to user."},"contest_type":{"type":"string","const":"raffle","title":"Contest Type","default":"raffle"},"end_condition":{"$ref":"#/components/schemas/ContestEndCondition"},"prizes":{"items":{"$ref":"#/components/schemas/ContestPrize"},"type":"array","minItems":1,"title":"Prizes"},"starts_at":{"type":"string","format":"date-time","title":"Starts At","description":"When the contest starts"},"terms_and_conditions":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Terms And Conditions"},"status":{"$ref":"#/components/schemas/ContestStatus","default":"active"},"country_isos":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Isos","description":"Contest is restricted to these countries. If null, all countries are allowed"},"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"Contest applies only to a single BP"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When this contest was created"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"When this contest was last modified. Does not include entries being created/modified"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At","description":"When the contest ended"},"end_reason":{"anyOf":[{"$ref":"#/components/schemas/ContestEndReason"},{"type":"null"}],"description":"The reason the contest ended"},"product_user_id":{"type":"string","title":"Product User Id"},"user_winnings":{"items":{"$ref":"#/components/schemas/ContestWinner"},"type":"array","title":"User Winnings","description":"The prizes won in this contest by the requested user"},"entry_type":{"type":"string","const":"cash","title":"Entry Type","default":"cash"},"entry_rule":{"$ref":"#/components/schemas/ContestEntryRule"},"current_amount":{"anyOf":[{"type":"integer"},{"type":"integer","minimum":0.0}],"title":"Current Amount","description":"Sum of all entry amounts","default":0},"current_participants":{"type":"integer","title":"Current Participants","description":"Count of unique participants","default":0},"user_amount":{"anyOf":[{"type":"integer"},{"type":"integer","minimum":0.0}],"title":"User Amount","description":"The total amount this user has entered"},"user_amount_today":{"anyOf":[{"type":"integer"},{"type":"integer","minimum":0.0}],"title":"User Amount Today","description":"The total amount this user has entered in the past 24 hours"},"current_win_probability":{"type":"number","title":"Current Win Probability","description":"Probability of this user winning 1 or more prizes, if the contestended right now","readOnly":true},"projected_win_probability":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Projected Win Probability","description":"Probability of this user winning 1 or more prizes, once the contestis projected to end. This value is only calculated if the contest has a target_entry_amountend condition.","readOnly":true}},"additionalProperties":false,"type":"object","required":["name","end_condition","product_id","product_user_id","user_amount","user_amount_today","current_win_probability","projected_win_probability"],"title":"RaffleUserView"},"RedemptionCurrency":{"type":"string","enum":["USD","CAD","GBP","EUR","INR","AUD","PLN","SEK","SGD","MXN"],"title":"RedemptionCurrency","description":"Supported Currencies for Foreign Redemptions"},"ReportTask":{"properties":{"bpuid":{"type":"string","maxLength":128,"minLength":3,"title":"product_user_id","description":"The unique identifier for the user, which is set by the Supplier.","examples":["app-user-9329ebd"]},"reasons":{"items":{"$ref":"#/components/schemas/ReportValue"},"type":"array","title":"Reasons","description":"The reason a user reported a task.\n\nAllowed values: \n - __0__ *(REASON_UNKNOWN)*: Used to indicate the user exited the task without giving feedback\n - __1__ *(TECHNICAL_ERROR)*: Task is in the wrong language/country, unanswerable question, won't proceed to next question, loading forever, error message\n - __2__ *(NO_REDIRECT)*: Task ended (completed or failed, and showed the user some dialog indicating the task was over), but failed to redirect\n - __3__ *(PRIVACY_INVASION)*: Asked for full name, home address, identity on another site, cc\n - __4__ *(UNCOMFORTABLE_TOPICS)*: Asked about children, employer, medical issues, drug use, STDs, etc.\n - __5__ *(ASKED_FOR_NOT_ALLOWED_ACTION)*: Asked to install software, signup/login to external site, access webcam, promise to pay using external site, etc.\n - __6__ *(BAD_ON_MOBILE)*: Task doesn't work well on a mobile device\n - __7__ *(DIDNT_LIKE)*: Too long, too boring, confusing, complicated, too many open-ended/free-response questions","examples":[[3,4]]},"notes":{"type":"string","title":"Notes","default":"","examples":["The survey wanted to watch me eat Haejang-guk"]}},"additionalProperties":false,"type":"object","required":["bpuid"],"title":"ReportTask"},"ReportValue":{"type":"integer","enum":[0,1,2,3,4,5,6,7],"title":"ReportValue","description":"The reason a user reported a task."},"Scope":{"type":"string","enum":["global","team","product"],"title":"Scope"},"SessionAdjustedStatus":{"type":"string","enum":["ac","af","pa"],"title":"SessionAdjustedStatus","description":"An adjusted_status is set if a session is adjusted by the marketplace\nafter the original return. A session can be adjusted multiple times.\nThis is the most recent status. If a session was originally a complete,\nwas adjusted to incomplete, then back to complete, the adjusted_status\nwill be None, but the adjusted_timestamp will be set to the most recent\nchange."},"SessionConfig":{"properties":{"max_session_len":{"type":"integer","maximum":5400.0,"minimum":60.0,"title":"Max Session Len","description":"The amount of time (in seconds) that a respondent may spend attempting to get into a survey within a session.If NULL, there is no limit.","default":600},"max_session_hard_retry":{"type":"integer","minimum":0.0,"title":"Max Session Hard Retry","description":"The number of surveys that a respondent may attempt within a session before the session is terminated.","default":5},"min_payout":{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$","title":"Min Payout","description":"The minimum amount the user should be paid for a complete. If \n no payout transformation is defined, the value is based on the BP's payout. \n If a payout transformation is defined, the min_payout is applied on the \n user's payout. Note, this is separate and distinct from the payout \n transformation's min payout. The payout transformation's min_payout does not \n care what the task's actual payout was. This min_payout will prevent\n the user from being show any tasks that would pay below this amount.","default":"0.14","examples":["0.50"]}},"type":"object","title":"SessionConfig","description":"Stores configuration related to the Session, a session being a users\nexperience attempting to do work."},"SessionEnterPayload":{"properties":{"event_type":{"type":"string","const":"session.enter","title":"Event Type","default":"session.enter"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"}},"type":"object","required":["country_iso"],"title":"SessionEnterPayload"},"SessionFinishPayload":{"properties":{"event_type":{"type":"string","const":"session.finish","title":"Event Type","default":"session.finish"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"duration_sec":{"type":"number","exclusiveMinimum":0.0,"title":"Duration Sec"},"status":{"$ref":"#/components/schemas/Status"},"status_code_1":{"anyOf":[{"$ref":"#/components/schemas/StatusCode1"},{"type":"null"}]},"status_code_2":{"anyOf":[{"$ref":"#/components/schemas/SessionStatusCode2"},{"type":"null"}]},"user_payout":{"anyOf":[{"type":"integer","maximum":4000.0,"minimum":0.0},{"type":"null"}],"title":"User Payout"}},"type":"object","required":["country_iso","duration_sec","status"],"title":"SessionFinishPayload"},"SessionStatusCode2":{"type":"integer","enum":[1,2,3,4,5,6,7,8,9,10,11,12,13],"title":"SessionStatusCode2","description":"__Status Detail__\nThis should be set if the Session.status_code_1 is SESSION_XXX_FAIL"},"ShippingCarrier":{"type":"string","enum":["USPS","FedEx","UPS","DHL"],"title":"ShippingCarrier"},"ShippingMethod":{"type":"string","enum":["Standard","Express","Two-Day","Overnight","Same Day"],"title":"ShippingMethod"},"SoftPairBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way. If the eligibility is conditional or ineligible, the uri will be null.","examples":[null]},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"eligibility":{"type":"string","enum":["conditional","unconditional","ineligible"],"title":"Eligibility","examples":["conditional"]},"missing_questions":{"items":{"type":"string"},"type":"array","title":"Missing Questions","examples":[["fb20fd4773304500b39c4f6de0012a5a"]]},"loi":{"type":"integer","title":"Loi","description":"this is the max loi of the contents","examples":[612]},"payout":{"type":"integer","title":"Payout","description":"this is the min payout of the contents","examples":[123]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","eligibility","loi","payout"],"title":"SoftPairBucket"},"SoftPairOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/SoftPairBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]},"question_info":{"additionalProperties":{"$ref":"#/components/schemas/UpkQuestion"},"type":"object","title":"Question Info","examples":[]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"SoftPairOfferwall","description":"This offerwall contains tasks for which the user has a conditional\neligibility. The questions that a user must answer to determine the\neligibility are included within each bucket. Additionally, the question\ndefinitions are included for convenience.\n\nOfferwall code: `37d1da64`"},"SoftPairOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/SoftPairOfferwall"}},"type":"object","required":["info","offerwall"],"title":"SoftPairOfferwallResponse"},"Source":{"type":"string","enum":["g","c","a","d","et","f","i","l","m","n","o","e","r","pr","p","rd","h","s","t","u","w"],"title":"Source"},"SourceConfig":{"properties":{"name":{"$ref":"#/components/schemas/Source"},"active":{"type":"boolean","title":"Active","default":true},"banned_countries":{"items":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},"type":"array","title":"Banned Countries"},"allow_mobile_ip":{"type":"boolean","title":"Allow Mobile Ip","default":true},"allow_pii_only_buyers":{"type":"boolean","title":"Allow Pii Only Buyers","description":"Allow Tasks from Buyers that want traffic that comes from Suppliers that can identify their users. Only supported on Pure Spectrum.","default":false},"allow_unhashed_buyers":{"type":"boolean","title":"Allow Unhashed Buyers","description":"Return Tasks from Buyers that don't have URL hashing enabled. Only supported on Pure Spectrum.","default":false},"withhold_profiling":{"type":"boolean","title":"Withhold Profiling","description":"For some Products, we may have privacy agreements prohibiting us from sharing information with the inventorySource. If True, don't add MRPQ (Market Research ProfilingQuestion) onto the entry link.","default":false},"pass_unconditional_eligible_unknowns":{"type":"boolean","title":"Pass Unconditional Eligible Unknowns","description":"Not used at the moment","default":true}},"type":"object","required":["name"],"title":"SourceConfig","description":"This could also be named \"BP:Marketplace Config\", as it describes the\nconfig for a BP on a single marketplace."},"SourcesConfig":{"properties":{"user_defined":{"items":{"$ref":"#/components/schemas/SourceConfig"},"type":"array","title":"User Defined"}},"type":"object","title":"SourcesConfig","description":"Describes the marketplaces or sources that a BP can access and their\nrespective configs,\naka 'BP:Marketplace Configs'"},"StarwallPlusBlockOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"StarwallPlusBlockOfferWall","description":"Same as the StarwallOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.\n\nOfferwall code: `7fa1b3f4`"},"StarwallPlusBlockOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/StarwallPlusBlockOfferWall"}},"type":"object","required":["info","offerwall"],"title":"StarwallPlusBlockOfferWallResponse"},"StarwallPlusBlockRecontactOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusRecontactBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"StarwallPlusBlockRecontactOfferWall","description":"Same as the StarwallOfferWall, but the buckets include contents, no\nbuckets are returned if the user is blocked, and each bucket includes\na recontact key.\n\nOfferwall code: `630db2a4`"},"StarwallPlusBlockRecontactOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/StarwallPlusBlockRecontactOfferWall"}},"type":"object","required":["info","offerwall"],"title":"StarwallPlusBlockRecontactOfferWallResponse"},"StarwallPlusOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"StarwallPlusOfferWall","description":"Same as the StarwallOfferWall, but the buckets include contents.\n\nOfferwall code: `5481f322`"},"StarwallPlusOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/StarwallPlusOfferWall"}},"type":"object","required":["info","offerwall"],"title":"StarwallPlusOfferWallResponse"},"StatisticalSummaryStat":{"properties":{"facet":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"number"}]},"propertyNames":{"enum":["country_iso","day","month"]},"type":"object","title":"Facet","description":"The grouping criteria","examples":[{"country_iso":"us"}]},"value":{"$ref":"#/components/schemas/StatisticalSummaryValue","description":"Statistical Summary for the given metric and facet"}},"type":"object","required":["facet","value"],"title":"StatisticalSummaryStat"},"StatisticalSummaryValue":{"properties":{"min":{"type":"number","title":"Min"},"max":{"type":"number","title":"Max"},"mean":{"type":"number","title":"Mean"},"q1":{"type":"number","title":"Q1"},"q2":{"type":"number","title":"Q2","description":"equal to the median"},"q3":{"type":"number","title":"Q3"},"lower_whisker":{"type":"number","title":"Lower Whisker","readOnly":true},"upper_whisker":{"type":"number","title":"Upper Whisker","readOnly":true}},"type":"object","required":["min","max","mean","q1","q2","q3","lower_whisker","upper_whisker"],"title":"StatisticalSummaryValue"},"StatsMessage":{"properties":{"kind":{"type":"string","const":"stats","title":"Kind","default":"stats"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"country_iso":{"anyOf":[{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},{"type":"null"}],"title":"Country Iso"},"data":{"$ref":"#/components/schemas/StatsSnapshot"}},"type":"object","required":["data"],"title":"StatsMessage"},"StatsSnapshot":{"properties":{"live_task_count":{"$ref":"#/components/schemas/AggregateBySource"},"task_created_count_last_1h":{"$ref":"#/components/schemas/AggregateBySource"},"task_created_count_last_24h":{"$ref":"#/components/schemas/AggregateBySource"},"live_tasks_max_payout":{"$ref":"#/components/schemas/MaxGaugeBySource","description":"In integer USDCents"},"country_iso":{"anyOf":[{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},{"type":"null"}],"title":"Country Iso"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"active_users_last_1h":{"type":"integer","minimum":0.0,"title":"Active Users Last 1H","description":"Count of users (in this product_id) that were active in the past 60 minutes.\n Behaviors that trigger active:\n - Request an offerwall\n - Enter an offerwall bucket\n - Request profiling questions\n - Submit profiling answers\n - Update user profile\n ","default":0},"active_users_last_24h":{"type":"integer","minimum":0.0,"title":"Active Users Last 24H","description":"Count of users (in this product_id) that were active in the past 24 hours.","default":0},"in_progress_users":{"type":"integer","minimum":0.0,"title":"In Progress Users","description":"Count of users that are currently doing work at this moment"},"signups_last_24h":{"type":"integer","minimum":0.0,"title":"Signups Last 24H","description":"Count of users created"},"session_enters_last_1h":{"type":"integer","minimum":0.0,"title":"Session Enters Last 1H"},"session_enters_last_24h":{"type":"integer","minimum":0.0,"title":"Session Enters Last 24H"},"session_fails_last_1h":{"type":"integer","minimum":0.0,"title":"Session Fails Last 1H"},"session_fails_last_24h":{"type":"integer","minimum":0.0,"title":"Session Fails Last 24H"},"session_completes_last_1h":{"type":"integer","minimum":0.0,"title":"Session Completes Last 1H"},"session_completes_last_24h":{"type":"integer","minimum":0.0,"title":"Session Completes Last 24H"},"sum_payouts_last_1h":{"type":"integer","minimum":0.0,"title":"Sum Payouts Last 1H","description":"In integer USDCents"},"sum_payouts_last_24h":{"type":"integer","minimum":0.0,"title":"Sum Payouts Last 24H","description":"In integer USDCents"},"session_avg_payout_last_24h":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Session Avg Payout Last 24H","description":"Average (actual) payout of all tasks completed in the past 24 hrs"},"session_avg_user_payout_last_24h":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Session Avg User Payout Last 24H","description":"Average (actual) user payout of all tasks completed in the past 24 hrs"},"session_fail_avg_loi_last_24h":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Session Fail Avg Loi Last 24H","description":"Average LOI of all tasks terminated in the past 24 hrs (excludes abandons)"},"session_complete_avg_loi_last_24h":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Session Complete Avg Loi Last 24H","description":"Average LOI of all tasks completed in the past 24 hrs"}},"type":"object","required":["in_progress_users","signups_last_24h","session_enters_last_1h","session_enters_last_24h","session_fails_last_1h","session_fails_last_24h","session_completes_last_1h","session_completes_last_24h","sum_payouts_last_1h","sum_payouts_last_24h","session_avg_payout_last_24h","session_avg_user_payout_last_24h","session_fail_avg_loi_last_24h","session_complete_avg_loi_last_24h"],"title":"StatsSnapshot"},"Status":{"type":"string","enum":["c","f","a","t"],"title":"Status","description":"The outcome of a session or wall event. If the session is still in\nprogress, the status will be NULL."},"StatusCode1":{"type":"integer","enum":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],"title":"StatusCode1","description":"__High level status code for outcome of the session.__\nThis should only be NULL if the Status is ABANDON or TIMEOUT"},"StatusInfoResponseFail":{"properties":{"info":{"$ref":"#/components/schemas/StatusSuccessFail"},"msg":{"type":"string","title":"Msg","description":"An optional message, if success is False","examples":["An error has occurred"]}},"type":"object","required":["info","msg"],"title":"StatusInfoResponseFail"},"StatusResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]}},"type":"object","required":["status"],"title":"StatusResponse"},"StatusResponseFailure":{"properties":{"status":{"type":"string","const":"failure","title":"Status","description":"The status of the API response.","examples":["failure"]},"msg":{"type":"string","title":"Msg","description":"An optional message, if the status is failure.","examples":["An error has occurred"]}},"type":"object","required":["status","msg"],"title":"StatusResponseFailure"},"StatusSuccessFail":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether the API response is successful.","default":false}},"type":"object","title":"StatusSuccessFail"},"StreakFulfillment":{"type":"string","enum":["active","complete"],"title":"StreakFulfillment","description":"What has to happen for a user to fulfill a period for a streak"},"StreakPeriod":{"type":"string","enum":["day","week","month"],"title":"StreakPeriod"},"StreakState":{"type":"string","enum":["active","at_risk","broken"],"title":"StreakState"},"SubscribeMessage":{"properties":{"kind":{"type":"string","const":"subscribe","title":"Kind","default":"subscribe"},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]}},"type":"object","required":["product_id"],"title":"SubscribeMessage"},"SupplierTag":{"type":"string","enum":["mobile","js-offerwall","double-opt-in","single-sign-on","phone-number-verified","test-a","test-b"],"title":"SupplierTag","description":"Available tags which can be used to annotate supplier traffic\n\nNote: should not include commas!"},"SupplyConfig":{"properties":{"policies":{"items":{"$ref":"#/components/schemas/SupplyPolicy"},"type":"array","title":"Policies"}},"type":"object","title":"SupplyConfig","description":"Describes the set of policies for how GRL can interact with marketplaces.\nThis is only used on the special \"global product\"."},"SupplyPolicy":{"properties":{"name":{"$ref":"#/components/schemas/Source"},"active":{"type":"boolean","title":"Active","default":true},"banned_countries":{"items":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},"type":"array","title":"Banned Countries"},"allow_mobile_ip":{"type":"boolean","title":"Allow Mobile Ip","default":true},"allow_pii_only_buyers":{"type":"boolean","title":"Allow Pii Only Buyers","description":"Allow Tasks from Buyers that want traffic that comes from Suppliers that can identify their users. Only supported on Pure Spectrum.","default":false},"allow_unhashed_buyers":{"type":"boolean","title":"Allow Unhashed Buyers","description":"Return Tasks from Buyers that don't have URL hashing enabled. Only supported on Pure Spectrum.","default":false},"withhold_profiling":{"type":"boolean","title":"Withhold Profiling","description":"For some Products, we may have privacy agreements prohibiting us from sharing information with the inventorySource. If True, don't add MRPQ (Market Research ProfilingQuestion) onto the entry link.","default":false},"pass_unconditional_eligible_unknowns":{"type":"boolean","title":"Pass Unconditional Eligible Unknowns","description":"Not used at the moment","default":true},"address":{"items":{"type":"string"},"type":"array","title":"Address","description":"address for the grpc GetOpps call"},"allow_vpn":{"type":"boolean","title":"Allow Vpn","default":false},"distribute_harmonizer_active":{"type":"boolean","title":"Distribute Harmonizer Active","default":true},"supplier_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supplier Id","description":"For some inventory Sources, we may partition traffic using different supplier accounts instead"},"team_ids":{"anyOf":[{"items":{"type":"string","maxLength":32,"minLength":32},"type":"array"},{"type":"null"}],"title":"Team Ids"},"product_ids":{"anyOf":[{"items":{"type":"string","maxLength":32,"minLength":32},"type":"array"},{"type":"null"}],"title":"Product Ids"},"integration_mode":{"$ref":"#/components/schemas/IntegrationMode","default":"platform"},"scope":{"$ref":"#/components/schemas/Scope","description":"There must be only 1 GLOBAL config per Source. We can have more than one TEAM/PRODUCT config per Source.","readOnly":true}},"type":"object","required":["name","address","scope"],"title":"SupplyPolicy","description":"One policy describing how GRL can interact with a marketplaces in a\ncertain way. This is only used on the special \"global product\", and then\ninternally in grpc logic."},"SurveyEligibilityCriterion":{"properties":{"question_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Question Id","examples":["71a367fb71b243dc89f0012e0ec91749"]},"property_code":{"anyOf":[{"type":"string","maxLength":64,"minLength":3,"pattern":"^[a-z]{1,2}\\:.*"},{"type":"null"}],"title":"Property Code","examples":["c:73629"]},"question_text":{"type":"string","title":"Question Text","examples":["What company administers the retirement plan for your current employer?"]},"qualifying_answer":{"items":{"type":"string"},"type":"array","title":"Qualifying Answer","description":"User answer(s) that satisfied at least one eligibility rule","examples":["121"]},"qualifying_answer_label":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Qualifying Answer Label","examples":["Fidelity Investments"]},"explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation","description":"Human-readable text explaining how a user's answer to this question affects eligibility","examples":["The company that administers your employer's retirement plan is **Fidelity Investments**."]},"rank":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Rank","description":"Lower values are shown more prominently in the UI"}},"type":"object","required":["question_id","property_code","question_text","qualifying_answer","qualifying_answer_label"],"title":"SurveyEligibilityCriterion","description":"Explanatory record of which question answers contributed\n to a user's eligibility for a survey.\nThis is INSUFFICIENT for determining eligibility to a task\n as it IGNORES logical operators, dependencies between criteria,\n and other requirements. It is only intended for the UI."},"TangoCashoutMethodData":{"properties":{"type":{"type":"string","const":"TANGO","title":"Type","default":"TANGO"},"utid":{"type":"string","title":"Utid","description":"tango utid"},"countries":{"items":{"type":"string"},"type":"array","title":"Countries"},"value_type":{"type":"string","enum":["variable","fixed"],"title":"Value Type"},"disclaimer":{"type":"string","title":"Disclaimer","default":""},"terms":{"type":"string","title":"Terms","default":""}},"type":"object","required":["utid","countries","value_type"],"title":"TangoCashoutMethodData"},"TaskEnterPayload":{"properties":{"event_type":{"type":"string","const":"task.enter","title":"Event Type","default":"task.enter"},"source":{"$ref":"#/components/schemas/Source"},"survey_id":{"type":"string","maxLength":32,"minLength":1,"title":"Survey Id","examples":["127492892"]},"quota_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Quota Id","description":"The marketplace's internal quota id"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"}},"type":"object","required":["source","survey_id","country_iso"],"title":"TaskEnterPayload"},"TaskFinishPayload":{"properties":{"event_type":{"type":"string","const":"task.finish","title":"Event Type","default":"task.finish"},"source":{"$ref":"#/components/schemas/Source"},"survey_id":{"type":"string","maxLength":32,"minLength":1,"title":"Survey Id","examples":["127492892"]},"quota_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Quota Id","description":"The marketplace's internal quota id"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"duration_sec":{"type":"number","exclusiveMinimum":0.0,"title":"Duration Sec"},"status":{"$ref":"#/components/schemas/Status"},"status_code_1":{"anyOf":[{"$ref":"#/components/schemas/StatusCode1"},{"type":"null"}]},"status_code_2":{"anyOf":[{"$ref":"#/components/schemas/WallStatusCode2"},{"type":"null"}]},"cpi":{"anyOf":[{"type":"integer","maximum":4000.0,"minimum":0.0},{"type":"null"}],"title":"Cpi"}},"type":"object","required":["source","survey_id","country_iso","duration_sec","status"],"title":"TaskFinishPayload"},"TaskStatusResponse":{"properties":{"tsid":{"type":"string","maxLength":32,"minLength":32,"title":"Tsid","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"product_id":{"type":"string","maxLength":32,"minLength":32,"title":"Product Id","description":"The BP ID of the associated respondent","examples":["1188cb21cb6741d79f614f6d02e9bc2a"]},"product_user_id":{"type":"string","maxLength":128,"minLength":3,"title":"Product User Id","description":"A unique identifier for each user, which is set by the Supplier","examples":["app-user-9329ebd"]},"started":{"type":"string","format":"date-time","title":"Started","description":"When the session was started"},"finished":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished","description":"When the session was finished"},"status":{"type":"integer","description":"The outcome of a session.\n - 0 - UNKNOWN\n - 1 - ENTER (the user has not yet returned)\n - 2 - INCOMPLETE (the user failed)\n - 3 - COMPLETE (the user completed the task)","examples":[3]},"payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"Payout","description":"The amount paid to the supplier, in integer USD cents","examples":[500]},"user_payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"User Payout","description":"If a payout transformation is configured on this account, this is the amount the user should earn, in integer USD cents","examples":[337]},"payout_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]},"user_payout_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Payout String","description":"If a payout transformation is configured on this account, this is the amount to display to the user","examples":["3370 Points"]},"kwargs":{"additionalProperties":{"type":"string"},"type":"object","title":"Kwargs","description":"Any extra url params used in the offerwall request will be passed back here"},"status_code_1":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"__High level status code for outcome of the session.__\nThis should only be NULL if the Status is ABANDON or TIMEOUT\n\nAllowed values: \n - __BUYER_FAIL__: User terminated in buyer survey\n - __BUYER_QUALITY_FAIL__: User terminated in buyer survey for quality reasons\n - __PS_FAIL__: User failed in marketplace's prescreener\n - __PS_QUALITY__: User rejected by marketplace for quality reasons\n - __PS_BLOCKED__: User is explicitly blocked by the marketplace. Note: on some marketplaces, users can have multiple PS_QUALITY terminations and still complete surveys.\n - __PS_OVERQUOTA__: User rejected by marketplace for over quota\n - __PS_DUPLICATE__: User rejected by marketplace for duplicate\n - __GRS_FAIL__: The user failed within the GRS Platform\n - __GRS_QUALITY_FAIL__: The user failed within the GRS Platform for quality reasons\n - __GRS_ABANDON__: The user abandoned/timed out within the GRS Platform\n - __PS_ABANDON__: The user abandoned/timed out within the marketplace's pre-screen system. Note: On most marketplaces, we have no way of distinguishing between this and BUYER_ABANDON. BUYER_ABANDON is used as the default, unless we know it is PS_ABANDON.\n - __BUYER_ABANDON__: The user abandoned/timed out within the client survey\n - __UNKNOWN__: The status code is not documented\n - __COMPLETE__: The user completed the task successfully\n - __MARKETPLACE_FAIL__: Something was wrong upon the user redirecting from the marketplace, e.g. no postback received, or url hashing failures.\n - __SESSION_START_FAIL__: User failed before being sent into a marketplace\n - __SESSION_CONTINUE_FAIL__: User failed between attempts\n - __SESSION_START_QUALITY_FAIL__: User failed before being sent into a marketplace for \"security\" reasons\n - __SESSION_CONTINUE_QUALITY_FAIL__: User failed between attempts for \"security\" reasons","examples":["COMPLETE"]},"status_code_2":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"__Status Detail__\nThis should be set if the Session.status_code_1 is SESSION_XXX_FAIL\n\nAllowed values: \n - __ENTRY_URL_MODIFICATION__: Unable to parse either the bucket_id, request_id, or nudge_id from the url\n - __UNRECOGNIZED_IP__: The client's IP failed GRIP lookup, or we failed to store it for some reason\n - __USER_IS_ANONYMOUS__: User is using an anonymous IP\n - __USER_IS_BLOCKED__: User is blocked\n - __USER_IS_RATE_LIMITED__: User is rate limited\n - __UNRECOGNIZED_DEVICE__: The client's useragent was not categorized as desktop, mobile, or tablet\n - __OFFERWALL_EXPIRED__: The user clicked after 5 min\n - __INTERNAL_ERROR__: Something unexpected happened\n - __OFFERWALL_COUNTRY_MISMATCH__: The user requested the offerwall for a different country than their IP address indicates\n - __INVALID_BUCKET_ID__: The bucket id indicated in the url does not exist. This is likely due to the user clicking on a bucket for an offerwall that has already been refreshed.\n - __NO_TASKS_AVAILABLE__: Not necessarily the user's fault. We thought we had surveys, but due to for e.g. the user entering on a different device than we thought, there really are none. If we get a lot of these, then that might indicate something is wrong.\n - __ATTEMPT_IS_SUSPICIOUS__: The entrance attempt was flagged by GRLIQ as suspicious\n - __GRLIQ_MISSING__: No GRLIQ forensics post was received","examples":[null]},"adjusted_status":{"anyOf":[{"$ref":"#/components/schemas/SessionAdjustedStatus"},{"type":"null"}],"description":"An adjusted_status is set if a session is adjusted by the marketplace\nafter the original return. A session can be adjusted multiple times.\nThis is the most recent status. If a session was originally a complete,\nwas adjusted to incomplete, then back to complete, the adjusted_status\nwill be None, but the adjusted_timestamp will be set to the most recent\nchange.\n\nAllowed values: \n - __ac__ *(ADJUSTED_TO_COMPLETE)*: Task was reconciled to complete\n - __af__ *(ADJUSTED_TO_FAIL)*: Task was reconciled to incomplete\n - __pa__ *(PAYOUT_ADJUSTMENT)*: The payout was changed. This applies to Sessions ONLY.","examples":[null]},"adjusted_timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Adjusted Timestamp","description":"When the adjusted status was last set.","examples":[null]},"adjusted_payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"Adjusted Payout","description":"The new payout after adjustment.","examples":[null]},"adjusted_user_payout":{"anyOf":[{"type":"integer","exclusiveMaximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"Adjusted User Payout","description":"The new user_payout after adjustment.","examples":[null]},"adjusted_user_payout_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Adjusted User Payout String","description":"The new user_payout_string after adjustment.","examples":[null]},"wall_events":{"anyOf":[{"items":{"$ref":"#/components/schemas/WallOut"},"type":"array"},{"type":"null"}],"title":"Wall Events"},"currency":{"type":"string","const":"USD","title":"Currency","default":"USD"},"final_status":{"type":"integer","title":"Final Status","description":"This is deprecated","default":0},"bpuid":{"type":"string","title":"Bpuid","readOnly":true}},"type":"object","required":["tsid","product_id","product_user_id","started","bpuid"],"title":"TaskStatusResponse","description":"The status of a session"},"TasksStatusResponse":{"properties":{"page":{"type":"integer","minimum":1.0,"title":"Page","description":"Page number","default":1},"size":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Size","description":"Page size","default":50},"total":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Total","description":"Total number of results"},"tasks_status":{"items":{"$ref":"#/components/schemas/TaskStatusResponse"},"type":"array","title":"Tasks Status"},"pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pages","description":"Total number of pages","readOnly":true}},"type":"object","required":["pages"],"title":"TasksStatusResponse"},"TopNPlusBlockOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"TopNPlusBlockOfferWall","description":"Same as the TopNOfferWall, but the buckets include contents and no\nbuckets are returned if the user is blocked.\n\nOfferwall code: `d48cce47`"},"TopNPlusBlockOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/TopNPlusBlockOfferWall"}},"type":"object","required":["info","offerwall"],"title":"TopNPlusBlockOfferWallResponse"},"TopNPlusBlockRecontactOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusRecontactBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"TopNPlusBlockRecontactOfferWall","description":"Same as the TopNOfferWall, but the buckets include contents, no buckets\nare returned if the user is blocked, and each bucket includes a\n`is_recontact` key.\n\nOfferwall code: `1e5f0af8`"},"TopNPlusBlockRecontactOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/TopNPlusBlockRecontactOfferWall"}},"type":"object","required":["info","offerwall"],"title":"TopNPlusBlockRecontactOfferWallResponse"},"TopNPlusBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"x":{"type":"integer","minimum":0.0,"title":"X","description":"For UI. Provides a dimensionality position for the bucket on the x-axis.","default":0,"examples":[0,1,2]},"y":{"type":"integer","minimum":0.0,"title":"Y","description":"For UI. Provides a dimensionality position for the bucket on the y-axis.","default":0,"examples":[0,1,2]},"name":{"type":"string","title":"Name","description":"Currently unused. Will always return empty string","default":""},"description":{"type":"string","title":"Description","description":"Currently unused. Will always return empty string","default":""},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"duration":{"$ref":"#/components/schemas/DurationSummary"},"payout":{"$ref":"#/components/schemas/PayoutSummary"},"quality_score":{"type":"number","title":"Quality Score"},"currency":{"type":"string","title":"Currency","description":"This will always be 'USD'","default":"USD","examples":["USD"]},"eligibility_criteria":{"items":{"$ref":"#/components/schemas/SurveyEligibilityCriterion"},"type":"array","title":"Eligibility Criteria","description":"The reasons the user is eligible for tasks in this bucket"},"eligibility_explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Eligibility Explanation","description":"Human-readable text explaining a user's eligibility for tasks in this bucket","examples":["You are a **47-year-old** **white** **male** with a *college degree*, who's employer's retirement plan is **Fidelity Investments**."]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","duration","payout","quality_score"],"title":"TopNPlusBucket"},"TopNPlusOfferWall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/TopNPlusBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"TopNPlusOfferWall","description":"Same as the TopNOfferWall, but the buckets include contents.\n\nOfferwall code: `b145b803`"},"TopNPlusOfferWallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/TopNPlusOfferWall"}},"type":"object","required":["info","offerwall"],"title":"TopNPlusOfferWallResponse"},"TopNPlusRecontactBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"x":{"type":"integer","minimum":0.0,"title":"X","description":"For UI. Provides a dimensionality position for the bucket on the x-axis.","default":0,"examples":[0,1,2]},"y":{"type":"integer","minimum":0.0,"title":"Y","description":"For UI. Provides a dimensionality position for the bucket on the y-axis.","default":0,"examples":[0,1,2]},"name":{"type":"string","title":"Name","description":"Currently unused. Will always return empty string","default":""},"description":{"type":"string","title":"Description","description":"Currently unused. Will always return empty string","default":""},"category":{"items":{"$ref":"#/components/schemas/CategoryAssociation"},"type":"array","title":"Category"},"contents":{"items":{"$ref":"#/components/schemas/BucketTask"},"type":"array","title":"Contents"},"duration":{"$ref":"#/components/schemas/DurationSummary"},"payout":{"$ref":"#/components/schemas/PayoutSummary"},"quality_score":{"type":"number","title":"Quality Score"},"is_recontact":{"type":"boolean","title":"Is Recontact"},"currency":{"type":"string","title":"Currency","description":"This will always be 'USD'","default":"USD","examples":["USD"]}},"additionalProperties":false,"type":"object","required":["id","uri","contents","duration","payout","quality_score","is_recontact"],"title":"TopNPlusRecontactBucket"},"UPKImportance":{"properties":{"task_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Task Count","description":"The number of live Tasks that use this UPK Question","examples":[47]},"task_score":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Task Score","description":"GRL's internal ranked score for the UPK Question","examples":[0.11175522477414712]},"marketplace_task_count":{"anyOf":[{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object"},{"type":"null"}],"title":"Marketplace Task Count","description":"The number of live Tasks that use this UPK Question per marketplace","examples":[{"d":23,"s":24}]}},"type":"object","title":"UPKImportance"},"USDeliveryAddress":{"properties":{"name_or_attn":{"type":"string","maxLength":50,"minLength":1,"title":"Name Or Attn"},"company":{"anyOf":[{"type":"string","maxLength":50,"minLength":1},{"type":"null"}],"title":"Company"},"phone_number":{"anyOf":[{"type":"string","maxLength":10,"minLength":10,"pattern":"^[0-9]+$"},{"type":"null"}],"title":"Phone Number"},"address":{"type":"string","maxLength":100,"minLength":1,"title":"Address"},"city":{"type":"string","maxLength":100,"minLength":1,"title":"City"},"state":{"type":"string","maxLength":2,"minLength":1,"title":"State"},"postal_code":{"type":"string","maxLength":10,"minLength":1,"title":"Postal Code"},"country":{"type":"string","title":"Country","default":"us"}},"type":"object","required":["name_or_attn","address","city","state","postal_code"],"title":"USDeliveryAddress"},"UpkItem":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","examples":["497b1fedec464151b063cd5367643ffa"]},"label":{"type":"string","maxLength":255,"title":"Label","examples":["high_school_completion"]},"description":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Description","examples":["Completed high school"]}},"type":"object","required":["id","label"],"title":"UpkItem"},"UpkProperty":{"properties":{"property_id":{"type":"string","maxLength":32,"minLength":32,"title":"Property Id","examples":["7a0635061fa64c98b43c6a3d15459f36"]},"property_label":{"type":"string","maxLength":255,"title":"Property Label","examples":["educational_attainment"]},"prop_type":{"$ref":"#/components/schemas/PropertyType","description":"\nAllowed values: \n - __i__ *(UPK_ITEM)*: UserProfileKnowledge Item\n - __n__ *(UPK_NUMERICAL)*: UserProfileKnowledge Numerical\n - __x__ *(UPK_TEXT)*: UserProfileKnowledge Text","default":"i"},"cardinality":{"$ref":"#/components/schemas/Cardinality","description":"\nAllowed values: \n - __*__ *(ZERO_OR_MORE)*: Zero or More\n - __?__ *(ZERO_OR_ONE)*: Zero or One","default":"?"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"gold_standard":{"type":"boolean","title":"Gold Standard","description":"A Gold-Standard question has been enumerated for all possible values (per country) as best as possible by GRL,allowing it to be mapped across inventory sources. A property not marked as Gold-Standard may have: 1) marketplace qid associations & 2) category associations, but doesn't have a defined 'range' (list of allowed itemsin a multiple choice question). This is used for exposing a user's profiling data & forthe Nudge API.","default":false},"allowed_items":{"anyOf":[{"items":{"$ref":"#/components/schemas/UpkItem"},"type":"array"},{"type":"null"}],"title":"Allowed Items"},"categories":{"items":{"$ref":"#/components/schemas/Category"},"type":"array","title":"Categories"}},"type":"object","required":["property_id","property_label","country_iso"],"title":"UpkProperty","description":"This used to be called \"QuestionInfo\", which is a bad name,\n as this describes a UPK Property, like \"educational_attainment\",\n not the question that asks for your education."},"UpkQuestion":{"properties":{"question_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Question Id"},"ext_question_id":{"anyOf":[{"type":"string","pattern":"^[a-z]{1,2}\\:.*"},{"type":"null"}],"title":"Ext Question Id","description":"what marketplace question this question links to"},"question_type":{"$ref":"#/components/schemas/UpkQuestionType"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"language_iso":{"type":"string","maxLength":3,"minLength":3,"pattern":"^[a-z]{3}$","title":"Language Iso"},"question_text":{"type":"string","minLength":1,"title":"Question Text","description":"The text shown to respondents"},"choices":{"anyOf":[{"items":{"$ref":"#/components/schemas/UpkQuestionChoice"},"type":"array"},{"type":"null"}],"title":"Choices"},"selector":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionSelectorMC"},{"$ref":"#/components/schemas/UpkQuestionSelectorTE"},{"$ref":"#/components/schemas/UpkQuestionSelectorSLIDER"},{"$ref":"#/components/schemas/UpkQuestionSelectorHIDDEN"}],"title":"Selector"},"configuration":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UpkQuestionConfigurationMC"},{"$ref":"#/components/schemas/UpkQuestionConfigurationTE"},{"$ref":"#/components/schemas/UpkQuestionConfigurationSLIDER"}],"discriminator":{"propertyName":"type","mapping":{"MC":"#/components/schemas/UpkQuestionConfigurationMC","SLIDER":"#/components/schemas/UpkQuestionConfigurationSLIDER","TE":"#/components/schemas/UpkQuestionConfigurationTE"}}},{"type":"null"}],"title":"Configuration"},"validation":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionValidation"},{"type":"null"}]},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]},"categories":{"items":{"$ref":"#/components/schemas/Category"},"type":"array","title":"Categories","description":"Categories associated with this question"},"explanation_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Template","description":"Human-readable template for explaining how a user's answer to this question affects eligibility","examples":["The company that administers your employer's retirement plan is {answer}."]},"explanation_fragment_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Fragment Template","description":"A very short, natural-language explanation fragment that can be combined with others into a single sentence","examples":["whose employer's retirement plan is {answer}"]}},"type":"object","required":["question_type","country_iso","language_iso","question_text","selector"],"title":"UpkQuestion","example":{"categories":[{"adwords_vertical_id":"396","label":"Politics","parent_uuid":"f66dddba61424ce5be2a38731450a0e1","path":"/News/Politics","uuid":"87b6d819f3ca4815bf1f135b1e829cc6"}],"choices":[{"choice_id":"1","choice_text":"Yes","exclusive":false,"order":0},{"choice_id":"2","choice_text":"No","exclusive":false,"order":1}],"country_iso":"us","importance":{"marketplace_task_count":{"d":9,"s":20,"w":20},"task_count":49,"task_score":3.3401743283265684},"language_iso":"eng","marketplace_task_count":{"d":9,"s":20,"w":20},"question_id":"fb20fd4773304500b39c4f6de0012a5a","question_text":"Are you registered to vote at your present address, or not?","question_type":"MC","selector":"SA","task_count":49,"task_score":3.3401743283265684}},"UpkQuestionChoice":{"properties":{"choice_id":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[\\w\\s\\.\\-]+$","title":"Choice Id","description":"The unique identifier for a response to a qualification"},"choice_text":{"type":"string","minLength":1,"title":"Choice Text","description":"The response text shown to respondents"},"order":{"type":"integer","minimum":0.0,"title":"Order"},"group":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group"},"exclusive":{"type":"boolean","title":"Exclusive","description":"If answer is exclusive, it can be the only option selected","default":false},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]}},"type":"object","required":["choice_id","choice_text","order"],"title":"UpkQuestionChoice"},"UpkQuestionChoiceOut":{"properties":{"choice_id":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[\\w\\s\\.\\-]+$","title":"Choice Id","description":"The unique identifier for a response to a qualification"},"choice_text":{"type":"string","minLength":1,"title":"Choice Text","description":"The response text shown to respondents"},"order":{"type":"integer","minimum":0.0,"title":"Order"},"group":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group"},"exclusive":{"type":"boolean","title":"Exclusive","description":"If answer is exclusive, it can be the only option selected","default":false},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]}},"type":"object","required":["choice_id","choice_text","order"],"title":"UpkQuestionChoiceOut"},"UpkQuestionConfigurationMC":{"properties":{"max_select":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Select"}},"additionalProperties":false,"type":"object","title":"UpkQuestionConfigurationMC"},"UpkQuestionConfigurationSLIDER":{"properties":{"slider_min":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Min"},"slider_max":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Max"},"slider_start":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Start"},"slider_step":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Slider Step"}},"type":"object","title":"UpkQuestionConfigurationSLIDER"},"UpkQuestionConfigurationTE":{"properties":{"max_length":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Length","description":"Maximum str length of any input. Meant as an easy, nonregex based check."},"min_length":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Min Length","description":"Minimum str length of any input. Meant as an easy, nonregex based check."}},"additionalProperties":false,"type":"object","title":"UpkQuestionConfigurationTE"},"UpkQuestionOut":{"properties":{"question_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Question Id"},"ext_question_id":{"anyOf":[{"type":"string","pattern":"^[a-z]{1,2}\\:.*"},{"type":"null"}],"title":"Ext Question Id","description":"what marketplace question this question links to"},"question_type":{"$ref":"#/components/schemas/UpkQuestionType"},"country_iso":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$","title":"Country Iso"},"language_iso":{"type":"string","maxLength":3,"minLength":3,"pattern":"^[a-z]{3}$","title":"Language Iso"},"question_text":{"type":"string","minLength":1,"title":"Question Text","description":"The text shown to respondents"},"choices":{"anyOf":[{"items":{"$ref":"#/components/schemas/UpkQuestionChoiceOut"},"type":"array"},{"type":"null"}],"title":"Choices"},"selector":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionSelectorMC"},{"$ref":"#/components/schemas/UpkQuestionSelectorTE"},{"$ref":"#/components/schemas/UpkQuestionSelectorSLIDER"},{"$ref":"#/components/schemas/UpkQuestionSelectorHIDDEN"}],"title":"Selector"},"configuration":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/UpkQuestionConfigurationMC"},{"$ref":"#/components/schemas/UpkQuestionConfigurationTE"},{"$ref":"#/components/schemas/UpkQuestionConfigurationSLIDER"}],"discriminator":{"propertyName":"type","mapping":{"MC":"#/components/schemas/UpkQuestionConfigurationMC","SLIDER":"#/components/schemas/UpkQuestionConfigurationSLIDER","TE":"#/components/schemas/UpkQuestionConfigurationTE"}}},{"type":"null"}],"title":"Configuration"},"validation":{"anyOf":[{"$ref":"#/components/schemas/UpkQuestionValidation"},{"type":"null"}]},"importance":{"anyOf":[{"$ref":"#/components/schemas/UPKImportance"},{"type":"null"}]},"categories":{"items":{"$ref":"#/components/schemas/Category"},"type":"array","title":"Categories","description":"Categories associated with this question"},"explanation_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Template","description":"Human-readable template for explaining how a user's answer to this question affects eligibility","examples":["The company that administers your employer's retirement plan is {answer}."]},"explanation_fragment_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation Fragment Template","description":"A very short, natural-language explanation fragment that can be combined with others into a single sentence","examples":["whose employer's retirement plan is {answer}"]},"task_count":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Task Count","description":"The number of live Tasks that use this UPK Question","examples":[47]},"task_score":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Task Score","description":"GRL's internal ranked score for the UPK Question","examples":[0.11175522477414712]},"marketplace_task_count":{"anyOf":[{"additionalProperties":{"type":"integer","minimum":0.0},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object"},{"type":"null"}],"title":"Marketplace Task Count","description":"The number of live Tasks that use this UPK Question per marketplace","examples":[{"d":23,"s":24}]}},"type":"object","required":["question_type","country_iso","language_iso","question_text","selector"],"title":"UpkQuestionOut","example":{"categories":[{"adwords_vertical_id":"396","label":"Politics","parent_uuid":"f66dddba61424ce5be2a38731450a0e1","path":"/News/Politics","uuid":"87b6d819f3ca4815bf1f135b1e829cc6"}],"choices":[{"choice_id":"1","choice_text":"Yes","exclusive":false,"order":0},{"choice_id":"2","choice_text":"No","exclusive":false,"order":1}],"country_iso":"us","importance":{"marketplace_task_count":{"d":9,"s":20,"w":20},"task_count":49,"task_score":3.3401743283265684},"language_iso":"eng","marketplace_task_count":{"d":9,"s":20,"w":20},"question_id":"fb20fd4773304500b39c4f6de0012a5a","question_text":"Are you registered to vote at your present address, or not?","question_type":"MC","selector":"SA","task_count":49,"task_score":3.3401743283265684}},"UpkQuestionResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"questions":{"items":{"$ref":"#/components/schemas/UpkQuestionOut"},"type":"array","title":"Questions"},"consent_questions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Consent Questions","description":"For internal use"},"special_questions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Special Questions","description":"For internal use"},"count":{"type":"integer","minimum":0.0,"title":"Count","description":"The number of questions returned"}},"type":"object","required":["status","questions","count"],"title":"UpkQuestionResponse"},"UpkQuestionSelectorHIDDEN":{"type":"string","enum":["HIDDEN"],"title":"UpkQuestionSelectorHIDDEN"},"UpkQuestionSelectorMC":{"type":"string","enum":["SA","MA","DL","SB","MSB"],"title":"UpkQuestionSelectorMC"},"UpkQuestionSelectorSLIDER":{"type":"string","enum":["HSLIDER","VSLIDER"],"title":"UpkQuestionSelectorSLIDER"},"UpkQuestionSelectorTE":{"type":"string","enum":["SL","ML","ETB"],"title":"UpkQuestionSelectorTE"},"UpkQuestionType":{"type":"string","enum":["MC","TE","SLIDER","HIDDEN"],"title":"UpkQuestionType"},"UpkQuestionValidation":{"properties":{"patterns":{"anyOf":[{"items":{"$ref":"#/components/schemas/PatternValidation"},"type":"array","minItems":1},{"type":"null"}],"title":"Patterns"}},"type":"object","required":["patterns"],"title":"UpkQuestionValidation"},"User":{"properties":{"id":{"anyOf":[{"type":"integer","exclusiveMaximum":2147483648.0,"exclusiveMinimum":0.0},{"type":"null"}],"title":"Id"},"uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Uuid","examples":["0f85f1ec17f14621a06c687de5ddafca"]},"product":{"anyOf":[{"$ref":"#/components/schemas/Product"},{"type":"null"}]},"product_id":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Product Id","examples":["4fe381fb7186416cb443a38fa66c6557"]},"product_user_id":{"anyOf":[{"type":"string","maxLength":128,"minLength":3},{"type":"null"}],"title":"Product User Id","description":"A unique identifier for each user, which is set by the Supplier. It should not contain any sensitive informationlike email or names, and should avoid using anyincrementing values.","examples":["app-user-9329ebd"]},"blocked":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Blocked","default":false},"created":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created","description":"When the user was created on the GRL platform."},"last_seen":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Seen","description":"When the user was last seen on, or acting on anypart of the GRL platform."},"audit_log":{"anyOf":[{"items":{"$ref":"#/components/schemas/AuditLog"},"type":"array"},{"type":"null"}],"title":"Audit Log"},"transactions":{"anyOf":[{"items":{"$ref":"#/components/schemas/LedgerTransaction"},"type":"array"},{"type":"null"}],"title":"Transactions"},"location_history":{"anyOf":[{"items":{"$ref":"#/components/schemas/GeoIPInformation"},"type":"array"},{"type":"null"}],"title":"Location History"}},"additionalProperties":false,"type":"object","title":"User"},"UserCreateConfig":{"properties":{"min_hourly_create_limit":{"type":"integer","minimum":0.0,"title":"Min Hourly Create Limit","description":"The smallest allowed value for the hourly user create limit.","default":0},"max_hourly_create_limit":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Hourly Create Limit","description":"The largest allowed value for the hourly user create limit. If None, the hourly create limit is unconstrained."}},"type":"object","title":"UserCreateConfig","description":"Stores configuration for the user creation experience.\n\nThe user creation limit is determined dynamically based on the median\n daily completion rate. min_hourly_create_limit &\n max_hourly_create_limit can be used to constrain the dynamically\n determined rate limit within set values."},"UserDisplayedWalletBalance":{"properties":{"currency":{"type":"string","maxLength":32,"title":"Currency"},"amount":{"type":"integer","title":"Amount","description":"Displayed balance in the currency's smallest ledger unit."},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String"}},"type":"object","required":["currency","amount"],"title":"UserDisplayedWalletBalance","description":"Combined user-visible balance for one ledger currency."},"UserHealthConfig":{"properties":{"banned_countries":{"items":{"type":"string","maxLength":2,"minLength":2,"pattern":"^[a-z]{2}$"},"type":"array","title":"Banned Countries"},"allow_ban_iphist":{"type":"boolean","title":"Allow Ban Iphist","default":true}},"type":"object","title":"UserHealthConfig"},"UserInfo":{"properties":{"user_profile_knowledge":{"items":{"$ref":"#/components/schemas/UserProfileKnowledge"},"type":"array","title":"User Profile Knowledge"},"marketplace_profile_knowledge":{"items":{"$ref":"#/components/schemas/MarketProfileKnowledge"},"type":"array","title":"Marketplace Profile Knowledge"}},"type":"object","title":"UserInfo"},"UserInfoResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"user_profile":{"$ref":"#/components/schemas/UserInfo"}},"type":"object","required":["status","user_profile"],"title":"UserInfoResponse"},"UserLedgerTransactionTaskAdjustment":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI","default":"Task Adjustment"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"bp_adjustment","title":"Tx Type","default":"bp_adjustment"},"tsid":{"type":"string","maxLength":32,"minLength":32,"title":"Tsid","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","amount","tsid","url","amount_string"],"title":"UserLedgerTransactionTaskAdjustment","example":{"amount":-38,"amount_string":"$-0.38","created":"2026-09-09T18:52:57.514390Z","description":"Task Adjustment","tsid":"f9830cbc0fe345c394726265f15f9638","tx_type":"bp_adjustment","url":"https://fsb.generalresearch.com/4c1a9fb5bc8d46a8a5a07900662483bc/status/f9830cbc0fe345c394726265f15f9638/"}},"UserLedgerTransactionTaskComplete":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI","default":"Task Complete"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"bp_payment","title":"Tx Type","default":"bp_payment"},"tsid":{"type":"string","maxLength":32,"minLength":32,"title":"Tsid","description":"A unique identifier for the session","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","amount","tsid","url","amount_string"],"title":"UserLedgerTransactionTaskComplete","description":"In a BP with user wallet enabled, the task-complete transaction would have\nline items for both the credit to the bp_wallet_account and credit to\nuser_account. This is the user-detail, so we've only caring about the\nuser's payment.","example":{"amount":38,"amount_string":"$0.38","created":"2026-09-09T18:52:57.514841Z","description":"Task Complete","tsid":"423f5ae084304bbbbc1f6ffda1b1c21b","tx_type":"bp_payment","url":"https://fsb.generalresearch.com/1d00ab8d467646f39d142b4b7145db17/status/423f5ae084304bbbbc1f6ffda1b1c21b/"}},"UserLedgerTransactionTypeSummary":{"properties":{"entry_count":{"type":"integer","minimum":0.0,"title":"Entry Count","default":0},"min_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Amount","description":"positive or negative USDCent"},"max_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Amount","description":"positive or negative USDCent"},"total_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Amount","description":"positive or negative USDCent"}},"type":"object","title":"UserLedgerTransactionTypeSummary"},"UserLedgerTransactionTypesSummary":{"properties":{"bp_adjustment":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"},"bp_payment":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"},"user_bonus":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"},"user_payout_request":{"$ref":"#/components/schemas/UserLedgerTransactionTypeSummary"}},"type":"object","title":"UserLedgerTransactionTypesSummary"},"UserLedgerTransactionUserBonus":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI","default":"Compensation Bonus"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"user_bonus","title":"Tx Type","default":"user_bonus"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","amount","url","amount_string"],"title":"UserLedgerTransactionUserBonus","example":{"amount":100,"amount_string":"$1.00","created":"2026-09-09T18:52:57.513921Z","description":"Compensation Bonus","tx_type":"user_bonus"}},"UserLedgerTransactionUserPayout":{"properties":{"created":{"type":"string","format":"date-time","title":"Created","description":"When the Transaction was created"},"description":{"type":"string","maxLength":255,"title":"Description","description":"External description suitable for UI"},"amount":{"type":"integer","title":"Amount","description":"The net amount affecting the user's wallet, in USDCents. Positive means the user's balance increased; negative means it decreased.","examples":[500,-250]},"balance_after":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Balance After"},"tx_type":{"type":"string","const":"user_payout_request","title":"Tx Type","default":"user_payout_request"},"payout_id":{"type":"string","maxLength":32,"minLength":32,"title":"Payout Id","description":"A unique identifier for the payout","examples":["a3848e0a53d64f68a74ced5f61b6eb68"]},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"A link to where the user can get more details about this transaction","readOnly":true},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String","description":"The 'amount' with the payout_format applied.","readOnly":true}},"additionalProperties":false,"type":"object","required":["created","description","amount","payout_id","url","amount_string"],"title":"UserLedgerTransactionUserPayout","example":{"amount":-5,"amount_string":"$-0.05","created":"2026-09-09T18:52:57.513399Z","description":"HIT Reward","payout_id":"af49e7a108c54c5b926ff97c0e177369","tx_type":"user_payout_request","url":"https://fsb.generalresearch.com/5ad58af0af3f49f39b8f480dfac856f3/cashout/af49e7a108c54c5b926ff97c0e177369/"}},"UserLedgerTransactionsResponse":{"properties":{"page":{"type":"integer","minimum":1.0,"title":"Page","description":"Page number","default":1},"size":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Size","description":"Page size","default":50},"total":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Total","description":"Total number of results"},"transactions":{"items":{"oneOf":[{"$ref":"#/components/schemas/UserLedgerTransactionUserPayout"},{"$ref":"#/components/schemas/UserLedgerTransactionUserBonus"},{"$ref":"#/components/schemas/UserLedgerTransactionTaskAdjustment"},{"$ref":"#/components/schemas/UserLedgerTransactionTaskComplete"}],"discriminator":{"propertyName":"tx_type","mapping":{"bp_adjustment":"#/components/schemas/UserLedgerTransactionTaskAdjustment","bp_payment":"#/components/schemas/UserLedgerTransactionTaskComplete","user_bonus":"#/components/schemas/UserLedgerTransactionUserBonus","user_payout_request":"#/components/schemas/UserLedgerTransactionUserPayout"}}},"type":"array","title":"Transactions"},"summary":{"$ref":"#/components/schemas/UserLedgerTransactionTypesSummary"},"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pages","description":"Total number of pages","readOnly":true}},"type":"object","required":["summary","status","pages"],"title":"UserLedgerTransactionsResponse"},"UserLedgerWallet":{"properties":{"amount":{"type":"integer","title":"Amount","description":"(USD cents) The amount in the user's wallet."},"redeemable_amount":{"type":"integer","minimum":0.0,"title":"Redeemable Amount","description":"(USD cents) The amount in the user's wallet this is currently redeemable."},"payout_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payout Format"},"amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount String"},"redeemable_amount_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redeemable Amount String"},"account_uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Account Uuid","description":"A unique identifier for this Ledger Account","examples":["c3c3566b5b1b4961b63a5670a2dc923d"]},"account_type":{"type":"string","enum":["user_wallet","user_attempt_credit"],"title":"Account Type"},"currency":{"type":"string","maxLength":32,"title":"Currency","default":"USD"},"display_name":{"type":"string","maxLength":64,"title":"Display Name","description":"Human-readable description of the Ledger Account"}},"type":"object","required":["amount","redeemable_amount","account_uuid","account_type","display_name"],"title":"UserLedgerWallet","description":"A user-owned ledger account exposed by the wallets endpoint.","example":{"amount":123,"amount_string":"1230 Points","payout_format":"{payout*10:,.0f} Points","redeemable_amount":100,"redeemable_amount_string":"1000 Points"}},"UserLedgerWallets":{"properties":{"wallets":{"items":{"$ref":"#/components/schemas/UserLedgerWallet"},"type":"array","title":"Wallets"},"displayed_balances":{"items":{"$ref":"#/components/schemas/UserDisplayedWalletBalance"},"type":"array","title":"Displayed Balances"}},"type":"object","title":"UserLedgerWallets"},"UserPayoutEvent":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Payout Event Unique Identifier","examples":["9453cd076713426cb68d05591c7145aa"]},"debit_account_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Debit Account Uuid","description":"The LedgerAccount.uuid that money is being requested from. Thie User or Brokerage Product is retrievable through the LedgerAccount.reference_uuid","examples":["18298cb1583846fbb06e4747b5310693"]},"cashout_method_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Cashout Method Uuid","description":"References a row in the account_cashoutmethod table. This is the cashout method that was used to request this payout. (A cashout is the same thing as a payout)","examples":["a6dc1fc1bf934557b952f253dee12813"]},"created":{"type":"string","format":"date-time","title":"Created"},"amount":{"type":"integer","exclusiveMaximum":9.223372036854776e+18,"exclusiveMinimum":0.0,"title":"Amount","description":"The USDCent amount int. This cannot be 0 or negative","examples":[531]},"status":{"anyOf":[{"$ref":"#/components/schemas/PayoutStatus"},{"type":"null"}],"description":" - `PENDING` = PENDING\n - `APPROVED` = APPROVED\n - `REJECTED` = REJECTED\n - `CANCELLED` = CANCELLED\n - `FAILED` = FAILED\n - `COMPLETE` = COMPLETE","default":"PENDING","examples":["COMPLETE"]},"ext_ref_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ext Ref Id"},"payout_type":{"$ref":"#/components/schemas/PayoutType","description":" - `PAYPAL` = PAYPAL\n - `TANGO` = TANGO\n - `DWOLLA` = DWOLLA\n - `ACH` = ACH\n - `WIRE` = WIRE\n - `CASH_IN_MAIL` = CASH_IN_MAIL\n - `PRIZE` = PRIZE\n - `AMT` = AMT\n - `AMT_BONUS` = AMT_BONUS\n - `AMT_ASSIGNMENT` = AMT_HIT","examples":["ACH"]},"request_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Request Data","description":"Stores payout-type-specific information that is used to request this payout from the external provider."},"order_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"$ref":"#/components/schemas/CashMailOrderData"},{"type":"null"}],"title":"Order Data","description":"Stores payout-type-specific order information that is returned from the external payout provider."},"account_reference_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Reference Type"},"account_reference_uuid":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Account Reference Uuid"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["debit_account_uuid","cashout_method_uuid","amount","payout_type"],"title":"UserPayoutEvent","description":"A user has requested to be paid from their wallet balance."},"UserProfile":{"properties":{"email_address":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email Address","examples":["contact@mail.com"]},"display_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Display Name","description":"A public name chosen by the user. Can be used in leaderboards or event stream."},"user":{"$ref":"#/components/schemas/User"},"marketplace_pids":{"additionalProperties":{"type":"string","maxLength":32,"minLength":32},"propertyNames":{"$ref":"#/components/schemas/Source"},"type":"object","title":"Marketplace Pids","description":"User's PID in marketplaces","examples":[{"c":"b507a2c00c3e481fb82f23655d142198","d":"deffe922063e4b9980206a62c3df2fba","i":"1dd9bd986794444eb97cb921aee5663f"}]},"streaks":{"items":{"$ref":"#/components/schemas/UserStreak"},"type":"array","title":"Streaks"},"email_md5":{"anyOf":[{"type":"string","maxLength":32,"minLength":32},{"type":"null"}],"title":"Email Md5","description":"MD5 hash of the email address","readOnly":true,"examples":["053fc3d5575362159e0c782abec83ffa"]},"email_sha1":{"anyOf":[{"type":"string","maxLength":40,"minLength":40},{"type":"null"}],"title":"Email Sha1","description":"SHA1 hash of the email address","readOnly":true,"examples":["6280fb76135b3585c0c5403be04844a0f0bae726"]},"email_sha256":{"anyOf":[{"type":"string","maxLength":64,"minLength":64},{"type":"null"}],"title":"Email Sha256","description":"SHA256 hash of the email address","readOnly":true,"examples":["8a098233e750f08de87d6053c06a58724287f34372368b6dc28b7ad4a77f3d39"]}},"additionalProperties":false,"type":"object","required":["user","email_md5","email_sha1","email_sha256"],"title":"UserProfile"},"UserProfileKnowledge":{"properties":{"property_id":{"type":"string","title":"Property Id"},"property_label":{"type":"string","title":"Property Label"},"translation":{"type":"string","title":"Translation"},"answer":{"items":{"$ref":"#/components/schemas/UserProfileKnowledgeAnswer"},"type":"array","title":"Answer"},"created":{"type":"string","format":"date-time","title":"Created","description":"When the User submitted this Profiling data"}},"type":"object","required":["property_id","property_label","translation","created"],"title":"UserProfileKnowledge"},"UserProfileKnowledgeAnswer":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"translation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Translation"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value"}},"type":"object","title":"UserProfileKnowledgeAnswer"},"UserProfileResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"user_profile":{"$ref":"#/components/schemas/UserProfile"}},"type":"object","required":["status","user_profile"],"title":"UserProfileResponse"},"UserProfileUpdateRequest":{"properties":{"email_address":{"type":"string","format":"email","title":"Email Address","examples":["contact@mail.com"]}},"additionalProperties":false,"type":"object","required":["email_address"],"title":"UserProfileUpdateRequest"},"UserProfilesResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"user_profiles":{"items":{"$ref":"#/components/schemas/UserProfile"},"type":"array","title":"User Profiles"}},"type":"object","required":["status","user_profiles"],"title":"UserProfilesResponse"},"UserQuestionAnswerIn":{"properties":{"question_id":{"type":"string","maxLength":32,"minLength":32,"title":"Question Id","examples":["fb20fd4773304500b39c4f6de0012a5a"]},"answer":{"items":{"type":"string","maxLength":5000,"minLength":1},"type":"array","maxItems":10,"minItems":1,"title":"Answer","description":"The user's answers to this question. Must pass the choice_id if the question is a Multiple Choice, or the actual text if the question is Text Entry","examples":[["1"]]}},"additionalProperties":false,"type":"object","required":["question_id","answer"],"title":"UserQuestionAnswerIn","description":"Send the answers to one or more questions for a user. A question is\nuniquely specified by the question_id key. The answer is: the choice_id\nif the question_type is \"MC\" the actual entered text if the\nquestion_type is \"TE\"\n\nTODO: look up the question_type from the question_id to apply MC or\n TE specific validation on the answer(s)"},"UserStreak":{"properties":{"country_iso":{"type":"string","title":"Country Iso"},"period":{"$ref":"#/components/schemas/StreakPeriod"},"fulfillment":{"$ref":"#/components/schemas/StreakFulfillment"},"current_streak":{"type":"integer","minimum":0.0,"title":"Current Streak"},"longest_streak":{"type":"integer","minimum":0.0,"title":"Longest Streak"},"state":{"$ref":"#/components/schemas/StreakState"},"last_fulfilled_period_start":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Last Fulfilled Period Start"},"timezone_name":{"type":"string","title":"Timezone Name","readOnly":true},"current_period_bounds":{"prefixItems":[{"type":"string","format":"date-time"},{"type":"string","format":"date-time"}],"type":"array","maxItems":2,"minItems":2,"title":"Current Period Bounds","readOnly":true},"last_fulfilled_period_bounds":{"anyOf":[{"prefixItems":[{"type":"string","format":"date-time"},{"type":"string","format":"date-time"}],"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Last Fulfilled Period Bounds","readOnly":true},"time_remaining_in_period":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Time Remaining In Period","readOnly":true}},"additionalProperties":false,"type":"object","required":["country_iso","period","fulfillment","current_streak","longest_streak","state","timezone_name","current_period_bounds","last_fulfilled_period_bounds","time_remaining_in_period"],"title":"UserStreak"},"UserWalletBalance":{"properties":{"amount":{"type":"integer","title":"Amount","description":"(USD cents) The amount in the user's wallet."},"redeemable_amount":{"type":"integer","minimum":0.0,"title":"Redeemable Amount","description":"(USD cents) The amount in the user's wallet this is currently redeemable."},"payout_format":{"type":"string","title":"Payout Format","description":"\nThe format describing the str representation of a payout. Typically, this would be displayed to a user.\nThe payout_format is similar to python format string with a subset of functionality supported.\nOnly float with a precision are supported along with an optional comma for a thousands separator.\nIn addition, a mathematical operator can be applied, such as dividing by 100. \nExamples are shown assuming payout = 100 (one dollar).\n- \"{payout*10:,.0f} Points\" -> \"1,000 Points\"\n- \"${payout/100:.2f}\" -> \"$1.00\"\n","examples":["{payout*10:,.0f} Points","${payout/100:.2f}","{payout:.0f}"]},"amount_string":{"type":"string","title":"Amount String","description":"The 'amount' with the payout_format applied. Can be displayed to the user."},"redeemable_amount_string":{"type":"string","title":"Redeemable Amount String","description":"The 'redeemable_amount' with the payout_format applied. Can be displayed to the user."}},"type":"object","required":["amount","redeemable_amount","payout_format","amount_string","redeemable_amount_string"],"title":"UserWalletBalance","example":{"amount":123,"amount_string":"1230 Points","payout_format":"{payout*10:,.0f} Points","redeemable_amount":100,"redeemable_amount_string":"1000 Points"}},"UserWalletBalanceResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status","description":"The status of the API response.","examples":["success"]},"msg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Msg","description":"An optional message, if the status is error.","examples":[""]},"wallet":{"$ref":"#/components/schemas/UserWalletBalance"}},"type":"object","required":["status","wallet"],"title":"UserWalletBalanceResponse"},"UserWalletConfig":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"If enabled, the users' wallets are managed.","default":false},"balance_type":{"type":"string","enum":["wallet_balance","redeemable_balance"],"title":"Balance Type","description":"The balance used as the user's displayed balance.","default":"wallet_balance"},"amt":{"type":"boolean","title":"Amt","description":"Uses Amazon Mechanical Turk","default":false},"supported_payout_types":{"items":{"$ref":"#/components/schemas/PayoutType"},"type":"array","title":"Supported Payout Types"},"min_cashout":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Min Cashout","description":"Minimum cashout amount. If enabled is True and no min_cashout is set, will default to $0.01.","examples":["10.00"]},"failed_attempt_credit":{"anyOf":[{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"},{"type":"null"}],"title":"Failed Attempt Credit","description":"Conditional credit awarded for an eligible failed attempt. None disables failed-attempt credits.","examples":["0.05",null]}},"type":"object","title":"UserWalletConfig","description":"Stores configuration for the user wallet handling"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WXETOfferwall":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier to reference a generated offerwall","examples":["7dc1d3aeb4844a6fab17ecd370b8bf1e"]},"availability_count":{"type":"integer","minimum":0.0,"title":"Availability Count","description":"Total opportunities available for specific bpuid respondent and parameters. This value changes frequently and can be used to determine if a respondent has potential tasks available, regardless of the offerwall type being requested. If the value is 0, no buckets will be generated.","examples":[42]},"attempted_live_eligible_count":{"type":"integer","minimum":0.0,"title":"Attempted Live Eligible Count","description":"Number of currently live opportunities for which the respondent meets all eligibility criteria but is excluded due to a prior attempt. Only includes surveys that are still live and otherwise eligible; does not include previously attempted surveys that are no longer available.","default":0,"examples":[7]},"buckets":{"items":{"$ref":"#/components/schemas/WXETOfferwallBucket"},"type":"array","title":"Buckets"},"offerwall_reasons":{"items":{"$ref":"#/components/schemas/OfferwallReason"},"type":"array","title":"Offerwall Reasons","description":"Explanations describing why so many or few opportunities are available.","examples":[["USER_BLOCKED","UNDER_MINIMUM_AGE"]]}},"additionalProperties":false,"type":"object","required":["id","availability_count"],"title":"WXETOfferwall","description":"Returns buckets from WXET as single tasks\nOfferwall code: `55a4e1a9`"},"WXETOfferwallBucket":{"properties":{"id":{"type":"string","maxLength":32,"minLength":32,"title":"Id","description":"Unique identifier this particular bucket","examples":["5ba2fe5010cc4d078fc3cc0b0cc264c3"]},"uri":{"type":"string","maxLength":2083,"minLength":1,"format":"uri","title":"Uri","description":"The URL to send a respondent into. Must not edit this URL in any way","examples":["https://task.generalresearch.com/api/v1/52d3f63b2709/797df4136c604a6c8599818296aae6d1/?i=5ba2fe5010cc4d078fc3cc0b0cc264c3&b=test&66482fb=e7baf5e"]},"duration":{"type":"integer","maximum":5400.0,"exclusiveMinimum":0.0,"title":"Duration","description":"The bucket's expected duration, in seconds"},"min_payout":{"type":"integer","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Min Payout","description":"The bucket's min payout, in usd cents"}},"additionalProperties":false,"type":"object","required":["id","uri","duration","min_payout"],"title":"WXETOfferwallBucket"},"WXETOfferwallResponse":{"properties":{"info":{"$ref":"#/components/schemas/OfferWallInfo"},"offerwall":{"$ref":"#/components/schemas/WXETOfferwall"}},"type":"object","required":["info","offerwall"],"title":"WXETOfferwallResponse"},"WallAdjustedStatus":{"type":"string","enum":["ac","af","ca","cc"],"title":"WallAdjustedStatus"},"WallOut":{"properties":{"uuid":{"type":"string","maxLength":32,"minLength":32,"title":"Uuid"},"source":{"$ref":"#/components/schemas/Source"},"buyer_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Buyer Id"},"req_survey_id":{"type":"string","maxLength":32,"title":"Req Survey Id"},"started":{"type":"string","format":"date-time","title":"Started"},"survey_id":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Survey Id"},"finished":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished"},"status":{"anyOf":[{"$ref":"#/components/schemas/Status"},{"type":"null"}]},"status_code_1":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"__High level status code for outcome of the session.__\nThis should only be NULL if the Status is ABANDON or TIMEOUT\n\nAllowed values: \n - __BUYER_FAIL__: User terminated in buyer survey\n - __BUYER_QUALITY_FAIL__: User terminated in buyer survey for quality reasons\n - __PS_FAIL__: User failed in marketplace's prescreener\n - __PS_QUALITY__: User rejected by marketplace for quality reasons\n - __PS_BLOCKED__: User is explicitly blocked by the marketplace. Note: on some marketplaces, users can have multiple PS_QUALITY terminations and still complete surveys.\n - __PS_OVERQUOTA__: User rejected by marketplace for over quota\n - __PS_DUPLICATE__: User rejected by marketplace for duplicate\n - __GRS_FAIL__: The user failed within the GRS Platform\n - __GRS_QUALITY_FAIL__: The user failed within the GRS Platform for quality reasons\n - __GRS_ABANDON__: The user abandoned/timed out within the GRS Platform\n - __PS_ABANDON__: The user abandoned/timed out within the marketplace's pre-screen system. Note: On most marketplaces, we have no way of distinguishing between this and BUYER_ABANDON. BUYER_ABANDON is used as the default, unless we know it is PS_ABANDON.\n - __BUYER_ABANDON__: The user abandoned/timed out within the client survey\n - __UNKNOWN__: The status code is not documented\n - __COMPLETE__: The user completed the task successfully\n - __MARKETPLACE_FAIL__: Something was wrong upon the user redirecting from the marketplace, e.g. no postback received, or url hashing failures.\n - __SESSION_START_FAIL__: User failed before being sent into a marketplace\n - __SESSION_CONTINUE_FAIL__: User failed between attempts\n - __SESSION_START_QUALITY_FAIL__: User failed before being sent into a marketplace for \"security\" reasons\n - __SESSION_CONTINUE_QUALITY_FAIL__: User failed between attempts for \"security\" reasons","examples":["COMPLETE"]},"status_code_2":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"This should be set if the Wall.status_code_1 is MARKETPLACE_FAIL\n\nAllowed values: \n - __URL_HASHING_CHECK_FAILED__: The redirect URL (coming back from the marketplace) failed hashing checks\n - __BROKEN_REDIRECT__: The redirect URL was missing required query params or was unparseable\n - __INVALID_REDIRECT__: The redirect URL was invalid or inconsistent in some way and as a result we could not determine the outcome. This could be if a redirect received did not match the user's most recent attempt.\n - __INVALID_MARKETPLACE_POSTBACK__: The redirect indicated a complete, but no/invalid Postback was received from the marketplace\n - __NO_MARKETPLACE_POSTBACK__: No/invalid Postback was received from the marketplace. Used in cases where the redirect does not contain a status.\n - __COMPLETE_TOO_FAST__: The marketplace indicates the user completed the survey, but we don't think this is valid due to speeding. Generally this cutoff is the 95th percentile of our calculated CompletionTime survey stat.\n - __INTERNAL_ERROR__: Something happened during the handling of this redirect (on our side)","examples":[null]},"ext_status_code_1":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Ext Status Code 1"},"ext_status_code_2":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Ext Status Code 2"},"ext_status_code_3":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Ext Status Code 3"},"report_value":{"anyOf":[{"$ref":"#/components/schemas/ReportValue"},{"type":"null"}]},"report_notes":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Report Notes"},"adjusted_status":{"anyOf":[{"$ref":"#/components/schemas/WallAdjustedStatus"},{"type":"null"}]},"adjusted_timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Adjusted Timestamp"},"user_cpi":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Cpi","description":"\n The amount the user would earn from completing this task, if the status was a complete.\n If the BP has no payout xform, the user_cpi is None. This is analogous to the session's\n user_payout.\n ","examples":[123]},"user_cpi_string":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Cpi String","description":"If a payout transformation is configured on this account, this is the amount to display to the user","examples":["123 Points"]}},"additionalProperties":false,"type":"object","required":["source","req_survey_id"],"title":"WallOut"},"WallStatusCode2":{"type":"integer","enum":[12,16,17,13,18,14,15],"title":"WallStatusCode2","description":"This should be set if the Wall.status_code_1 is MARKETPLACE_FAIL"},"YieldManConfig":{"properties":{"category_request":{"$ref":"#/components/schemas/OfferWallCategoryRequest"},"scoring_params":{"$ref":"#/components/schemas/OfferWallRequestYieldmanParams"}},"type":"object","title":"YieldManConfig"}}},"tags":[{"name":"Offerwall","description":"Generate and retrieve various offerwall groupings. These results should be called \"on the \n fly\" just before presenting the results to a respondent. Results greater than 3 minutes old should not be \n presented to the respondent. When a respondent takes any action on a generated offerwall (they go into a \n bucket), the offerwall should be discarded. Any subsequent bucket entrances will fail. The following reserved \n are reserved keywords. However, any additional query parameter that is provided, will be returned back in the \n TaskResponse response in the kwargs attribute.\n\n {'b', 'bp_user_id', 'bpuid', 'country_codes', 'country', 'cpi', 'currency', \n 'description', 'duration', 'entry_link', 'i', 'idx', 'info', 'ip', 'kwargs',\n 'l', 'lang_codes', 'languages', 'loi', 'name', 'payout', 'product_id', \n 'quality', 'quality_category', 'req_loi', 'status', 'task_uri', 'tasks', \n 'tsid', 'uri', 'url', 'country_iso', 'format', 'behavior'}"},{"name":"Status","description":"Retrieving the status of respondent attempts, either by brokerage account filtering, or a specific Task Status ID (TSID) that is provided in the redirect."}]} \ No newline at end of file
diff --git a/jb-ui/src/components/EventMarquee.tsx b/jb-ui/src/components/EventMarquee.tsx
index 4ce4f15..46508ff 100644
--- a/jb-ui/src/components/EventMarquee.tsx
+++ b/jb-ui/src/components/EventMarquee.tsx
@@ -1,230 +1,250 @@
-import { EventEnvelope, EventType, TaskEnterPayload, TaskFinishPayload } from "@/api_fsb";
-import { formatSecondsVerbose, formatSource, formatStatus, truncate } from "@/lib/utils";
+import {
+ EventEnvelope,
+ EventType,
+ TaskEnterPayload,
+ TaskFinishPayload,
+} from "@/api_fsb";
+import {
+ formatSecondsVerbose,
+ formatSource,
+ formatStatus,
+ truncate,
+} from "@/lib/utils";
import { selectAllEvents, selectCurrentSpeed } from "@/models/grlEventsSlice";
-import getUnicodeFlagIcon from 'country-flag-icons/unicode';
+import getUnicodeFlagIcon from "country-flag-icons/unicode";
import { useEffect, useRef, useState } from "react";
import { useSelector } from "react-redux";
// ─── Config ───────────────────────────────────────────────────────────────────
-const SPEED_EASING = 0.025; // how quickly speed transitions (per frame)
+const SPEED_EASING = 0.025; // how quickly speed transitions (per frame)
interface EventItemProps {
- event: EventEnvelope;
+ event: EventEnvelope;
}
const EventTaskEnter = ({ event }: EventItemProps) => {
- const payload = event.payload as TaskEnterPayload;
-
- return (
- <>
- <span className="px-2 text-lg">{getUnicodeFlagIcon(payload.country_iso)}</span>
- <p>
- {truncate(event.product_user_id!, 6, "*****")} Entered{" "}
- {formatSource(payload.source)}{" "}
- (#{truncate(payload.survey_id!, 5, "***")})
- </p>
- </>
- )
-}
+ const payload = event.payload as TaskEnterPayload;
+
+ return (
+ <>
+ <span className="px-2 text-lg">
+ {getUnicodeFlagIcon(payload.country_iso)}
+ </span>
+ <p>
+ {truncate(event.product_user_id!, 6, "*****")} Entered{" "}
+ {formatSource(payload.source)} (#
+ {truncate(payload.survey_id!, 5, "***")})
+ </p>
+ </>
+ );
+};
const EventTaskFinish = ({ event }: EventItemProps) => {
- const payload = event.payload as TaskFinishPayload;
-
- return (
- <>
- <span className="px-2 text-lg">{getUnicodeFlagIcon(event.payload.country_iso)}</span>
- <p>
- {truncate(event.product_user_id!, 6, "*****")}{" "}
- {formatStatus(payload.status)} {formatSource(payload.source)}{" "}
- (#{truncate(payload.survey_id!, 5, "***")}) in{" "}
- {formatSecondsVerbose(payload.duration_sec!)}
- </p>
- </>
- )
-}
+ const payload = event.payload as TaskFinishPayload;
+
+ return (
+ <>
+ <span className="px-2 text-lg">
+ {getUnicodeFlagIcon(event.payload.country_iso)}
+ </span>
+ <p>
+ {truncate(event.product_user_id!, 6, "*****")}{" "}
+ {formatStatus(payload.status)} {formatSource(payload.source)} (#
+ {truncate(payload.survey_id!, 5, "***")}) in{" "}
+ {formatSecondsVerbose(payload.duration_sec!)}
+ </p>
+ </>
+ );
+};
const EventUserCreated = ({ event }: EventItemProps) => {
-
- return (
- <>
- <span className="px-2 text-lg">{getUnicodeFlagIcon(event.payload.country_iso)}</span>
- <p>{truncate(event.product_user_id!, 6, "*****")} Created</p>
- </>
- )
-}
-
+ return (
+ <>
+ <span className="px-2 text-lg">
+ {getUnicodeFlagIcon(event.payload.country_iso)}
+ </span>
+ <p>{truncate(event.product_user_id!, 6, "*****")} Created</p>
+ </>
+ );
+};
const EventComponent = ({ event }: EventItemProps) => {
-
- const renderContent = () => {
- switch (event.event_type) {
- case EventType.TaskEnter:
- return <EventTaskEnter event={event} />
- case EventType.TaskFinish:
- return <EventTaskFinish event={event} />
- case EventType.UserCreated:
- return <EventUserCreated event={event} />
- default:
- return <><p>Unknown event</p></>
- }
+ const renderContent = () => {
+ switch (event.event_type) {
+ case EventType.TaskEnter:
+ return <EventTaskEnter event={event} />;
+ case EventType.TaskFinish:
+ return <EventTaskFinish event={event} />;
+ case EventType.UserCreated:
+ return <EventUserCreated event={event} />;
+ default:
+ return (
+ <>
+ <p>Unknown event</p>
+ </>
+ );
}
+ };
- return (
- <div key={event.event_uuid!}
- className="inline-flex items-center text-[10px]
- font-mono px-2">
- {renderContent()}
-
- {/* <span className="text-red-500 pl-5">◆</span> */}
- </div >
- )
-}
+ return (
+ <div
+ key={event.event_uuid!}
+ className="inline-flex items-center text-[10px]
+ font-mono px-2"
+ >
+ {renderContent()}
+ {/* <span className="text-red-500 pl-5">◆</span> */}
+ </div>
+ );
+};
// ─── Main Component ───────────────────────────────────────────────────────────
export default function NewsTicker() {
- // --- Redux ---
- const reduxItems = useSelector(selectAllEvents);
- const targetSpeedRedux = useSelector(selectCurrentSpeed); // px/sec
-
- // --- Scroll state (all refs — no re-renders from animation) ---
- const containerRef = useRef<HTMLDivElement | null>(null); // The ticker band
- const stripRef = useRef<HTMLDivElement | null>(null); // Scrolling strip
- const translateX = useRef(0);
- const currentSpeed = useRef(targetSpeedRedux);
- const targetSpeed = useRef(targetSpeedRedux);
-
- // Only state and refs persist across renders, the rest are re-initialized,
- // that is why this isn't just a standard variable.
- // Request Animation Frame reference (stores the animation frame ID)
- const rafRef = useRef<number | null>(null);
- const lastTime = useRef<number | null>(null);
-
- // --- Item tracking ---
- // Track which IDs are already in the scroller to only append
- // genuinely new ones.
- const seenUUIDs = useRef(new Set<string>());
- const pendingQueue = useRef<EventEnvelope[]>([]);
- const [scrollItems, setScrollItems] = useState<EventEnvelope[]>([]);
-
- // --- Sync Redux → pendingQueue (only new items) ---
- useEffect(() => {
- const newItems = reduxItems.filter((item) => !seenUUIDs.current.has(item.event_uuid!));
- if (newItems.length === 0) return;
-
- newItems.forEach(item => seenUUIDs.current.add(item.event_uuid!));
- pendingQueue.current.push(...newItems);
- }, [reduxItems]);
-
- // --- Sync target speed from Redux ---
- useEffect(() => {
- targetSpeed.current = targetSpeedRedux;
- }, [targetSpeedRedux]);
-
- // --- RAF loop ---
- useEffect(() => {
- // This timestamp is a "high-resolution timestamp" provided by
- // the browser, which is more accurate for measuring frame intervals
- // than Date.now()
- const loop = (timestamp: number) => {
- console.log("RAF loop, timestamp:", timestamp, lastTime.current);
-
- if (!lastTime.current) lastTime.current = timestamp;
- const delta = (timestamp - lastTime.current) / 1000;
- lastTime.current = timestamp;
-
- // Slow easement towards targetSpeed
- currentSpeed.current +=
- (targetSpeed.current - currentSpeed.current) * SPEED_EASING;
-
- // flush pending queue into React state
- if (pendingQueue.current.length > 0) {
- const incoming = pendingQueue.current.splice(0);
- setScrollItems((prev) => [...prev, ...incoming]);
- }
-
- // Advance strip, slides it over left by X pixels
- translateX.current -= currentSpeed.current * delta;
- if (stripRef.current) {
- stripRef.current.style.transform = `translateX(${translateX.current}px)`;
- }
-
- // prune items that have fully exited the left edge
- if (stripRef.current && containerRef.current) {
- const children = Array.from(stripRef.current.children);
- const containerLeft = containerRef.current.getBoundingClientRect().left;
- let pruneCount = 0;
- let removedWidth = 0;
-
- for (const child of children) {
- const rect = child.getBoundingClientRect();
- if (rect.right < containerLeft - 20) {
- pruneCount++;
- removedWidth += rect.width;
- } else {
- break;
- }
- }
-
- if (pruneCount > 0) {
- translateX.current += removedWidth;
- setScrollItems((prev) => prev.slice(pruneCount));
- }
- }
-
- // Assign the next loop
- rafRef.current = requestAnimationFrame(loop);
- };
-
- rafRef.current = requestAnimationFrame(loop);
- return () => cancelAnimationFrame(rafRef.current!);
- }, []);
-
- return (
- <div style={{
- minHeight: "3vh", display: "flex", flexDirection: "column",
- justifyContent: "center", alignItems: "center", gap: "0"
- }}>
-
- {/* Ticker wrapper */}
- <div style={{ width: "100%", position: "relative" }}>
-
- {/* The ticker band */}
- <div
- ref={containerRef}
- style={{
- overflow: "hidden",
- padding: "0",
- position: "relative",
- }}
- >
-
- {/* Scrolling strip */}
- <div
- ref={stripRef}
- style={{
- display: "inline-flex",
- alignItems: "center",
- whiteSpace: "nowrap",
- padding: "10px 0",
- willChange: "transform",
- position: "relative",
- zIndex: 2,
- }}
- >
- {scrollItems.map(item => (
- <EventComponent event={item} />
- ))}
-
- {/* Trailing spacer so new content doesn't immediately snap in */}
- <span style={{ paddingRight: "100vw", display: "inline-block" }} />
-
- </div>
- </div>
-
- </div>
+ // --- Redux ---
+ const reduxItems = useSelector(selectAllEvents);
+ const targetSpeedRedux = useSelector(selectCurrentSpeed); // px/sec
+
+ // --- Scroll state (all refs — no re-renders from animation) ---
+ const containerRef = useRef<HTMLDivElement | null>(null); // The ticker band
+ const stripRef = useRef<HTMLDivElement | null>(null); // Scrolling strip
+ const translateX = useRef(0);
+ const currentSpeed = useRef(targetSpeedRedux);
+ const targetSpeed = useRef(targetSpeedRedux);
+
+ // Only state and refs persist across renders, the rest are re-initialized,
+ // that is why this isn't just a standard variable.
+ // Request Animation Frame reference (stores the animation frame ID)
+ const rafRef = useRef<number | null>(null);
+ const lastTime = useRef<number | null>(null);
+
+ // --- Item tracking ---
+ // Track which IDs are already in the scroller to only append
+ // genuinely new ones.
+ const seenUUIDs = useRef(new Set<string>());
+ const pendingQueue = useRef<EventEnvelope[]>([]);
+ const [scrollItems, setScrollItems] = useState<EventEnvelope[]>([]);
+
+ // --- Sync Redux → pendingQueue (only new items) ---
+ useEffect(() => {
+ const newItems = reduxItems.filter(
+ (item) => !seenUUIDs.current.has(item.event_uuid!),
+ );
+ if (newItems.length === 0) return;
+
+ newItems.forEach((item) => seenUUIDs.current.add(item.event_uuid!));
+ pendingQueue.current.push(...newItems);
+ }, [reduxItems]);
+
+ // --- Sync target speed from Redux ---
+ useEffect(() => {
+ targetSpeed.current = targetSpeedRedux;
+ }, [targetSpeedRedux]);
+
+ // --- RAF loop ---
+ useEffect(() => {
+ // This timestamp is a "high-resolution timestamp" provided by
+ // the browser, which is more accurate for measuring frame intervals
+ // than Date.now()
+ const loop = (timestamp: number) => {
+ // console.log("RAF loop, timestamp:", timestamp, lastTime.current);
+
+ if (!lastTime.current) lastTime.current = timestamp;
+ const delta = (timestamp - lastTime.current) / 1000;
+ lastTime.current = timestamp;
+
+ // Slow easement towards targetSpeed
+ currentSpeed.current +=
+ (targetSpeed.current - currentSpeed.current) * SPEED_EASING;
+
+ // flush pending queue into React state
+ if (pendingQueue.current.length > 0) {
+ const incoming = pendingQueue.current.splice(0);
+ setScrollItems((prev) => [...prev, ...incoming]);
+ }
+
+ // Advance strip, slides it over left by X pixels
+ translateX.current -= currentSpeed.current * delta;
+ if (stripRef.current) {
+ stripRef.current.style.transform = `translateX(${translateX.current}px)`;
+ }
+
+ // prune items that have fully exited the left edge
+ if (stripRef.current && containerRef.current) {
+ const children = Array.from(stripRef.current.children);
+ const containerLeft = containerRef.current.getBoundingClientRect().left;
+ let pruneCount = 0;
+ let removedWidth = 0;
+
+ for (const child of children) {
+ const rect = child.getBoundingClientRect();
+ if (rect.right < containerLeft - 20) {
+ pruneCount++;
+ removedWidth += rect.width;
+ } else {
+ break;
+ }
+ }
+ if (pruneCount > 0) {
+ translateX.current += removedWidth;
+ setScrollItems((prev) => prev.slice(pruneCount));
+ }
+ }
+
+ // Assign the next loop
+ rafRef.current = requestAnimationFrame(loop);
+ };
+
+ rafRef.current = requestAnimationFrame(loop);
+ return () => cancelAnimationFrame(rafRef.current!);
+ }, []);
+
+ return (
+ <div
+ style={{
+ minHeight: "3vh",
+ display: "flex",
+ flexDirection: "column",
+ justifyContent: "center",
+ alignItems: "center",
+ gap: "0",
+ }}
+ >
+ {/* Ticker wrapper */}
+ <div style={{ width: "100%", position: "relative" }}>
+ {/* The ticker band */}
+ <div
+ ref={containerRef}
+ style={{
+ overflow: "hidden",
+ padding: "0",
+ position: "relative",
+ }}
+ >
+ {/* Scrolling strip */}
+ <div
+ ref={stripRef}
+ style={{
+ display: "inline-flex",
+ alignItems: "center",
+ whiteSpace: "nowrap",
+ padding: "10px 0",
+ willChange: "transform",
+ position: "relative",
+ zIndex: 2,
+ }}
+ >
+ {scrollItems.map((item) => (
+ <EventComponent event={item} />
+ ))}
+
+ {/* Trailing spacer so new content doesn't immediately snap in */}
+ <span style={{ paddingRight: "100vw", display: "inline-block" }} />
+ </div>
</div>
- );
+ </div>
+ </div>
+ );
}
diff --git a/jb-ui/src/components/Footer.tsx b/jb-ui/src/components/Footer.tsx
index 00c0101..e65255f 100644
--- a/jb-ui/src/components/Footer.tsx
+++ b/jb-ui/src/components/Footer.tsx
@@ -1,41 +1,50 @@
-import { useAppSelector } from "@/hooks";
+import { useGetMeQuery } from "@/models/authAPI";
const Footer = () => {
- const bpuid = useAppSelector(state => state.app.bpuid)
- const assignment_id = useAppSelector(state => state.app.assignment_id)
+ const { data: user } = useGetMeQuery();
- return (
- <div className="grid gap-1 grid-cols-1
+ return (
+ <div
+ className="grid gap-1 grid-cols-1
md:grid-cols-3
- text-xs">
- <div>
- <p>help: <a
- href={`mailto:support@jamesbillings67.com?subject=AMT Support Request: (${(bpuid ?? '-')}) ${(assignment_id ?? '–')}`}>
- support@jamesbillings67.com
- </a>
- </p>
- </div>
+ text-xs"
+ >
+ <div>
+ <p>
+ help:{" "}
+ <a
+ href={`mailto:support@jamesbillings67.com?subject=AMT Support Request: (${user?.product_user_id ?? "-"})`}
+ >
+ support@jamesbillings67.com
+ </a>
+ </p>
+ </div>
- <div>
- <p>made with <span className="text-rose-500">♥</span> by <a
- className="hover:cursor-pointer hover:text-pink"
- href="https://instagram.com/x0xMaximus"
- target="_blank">Max Nanis</a>
- </p>
- </div>
+ <div>
+ <p>
+ made with <span className="text-rose-500">♥</span> by{" "}
+ <a
+ className="hover:cursor-pointer hover:text-pink"
+ href="https://instagram.com/x0xMaximus"
+ target="_blank"
+ >
+ Max Nanis
+ </a>
+ </p>
+ </div>
- <div>
- <p>
- <a href="https://git.generalresearch.com/panels/amt-jb/"
- target="_blank">
- open source
- </a>
- </p>
- </div>
+ <div>
+ <p>
+ <a
+ href="https://git.generalresearch.com/panels/amt-jb/"
+ target="_blank"
+ >
+ open source
+ </a>
+ </p>
+ </div>
+ </div>
+ );
+};
- </div>
- )
-
-}
-
-export default Footer \ No newline at end of file
+export default Footer;
diff --git a/jb-ui/src/components/Profiling.tsx b/jb-ui/src/components/Profiling.tsx
index 9cefdda..b834c9f 100644
--- a/jb-ui/src/components/Profiling.tsx
+++ b/jb-ui/src/components/Profiling.tsx
@@ -1,536 +1,572 @@
-import {
- UpkQuestionChoice
-} from "@/api_fsb";
-import {
- ChevronRightIcon
-} from "lucide-react";
+import { UpkQuestionChoice } from "@/api_fsb";
+import { useGetMeQuery } from "@/models/authAPI";
+import { ChevronRightIcon } from "lucide-react";
import { KeyboardEvent, MouseEvent, useEffect, useRef, useState } from "react";
-import { useAppDispatch, useAppSelector } from "@/hooks";
+import { useAppDispatch } from "@/hooks";
import { bpid } from "@/lib/utils";
import {
- createColumnHelper,
- flexRender,
- getCoreRowModel,
- getFilteredRowModel,
- getSortedRowModel,
- RowModel,
- RowSelectionState,
- useReactTable,
-} from '@tanstack/react-table';
+ createColumnHelper,
+ flexRender,
+ getCoreRowModel,
+ getFilteredRowModel,
+ getSortedRowModel,
+ RowModel,
+ RowSelectionState,
+ useReactTable,
+} from "@tanstack/react-table";
import { clsx } from "clsx";
import {
- Pagination,
- PaginationContent,
- PaginationItem,
- PaginationLink
+ Pagination,
+ PaginationContent,
+ PaginationItem,
+ PaginationLink,
} from "@/components/ui/pagination";
import {
- addAnswers,
- fetchNewQuestions,
- goToNextQuestion,
- ProfileQuestion,
- questionsSelectors,
- saveAnswer,
- selectActiveQuestion,
- selectActiveQuestionValidation,
- selectAllQuestions,
- setActiveQuestion
+ addAnswers,
+ fetchNewQuestions,
+ goToNextQuestion,
+ ProfileQuestion,
+ questionsSelectors,
+ saveAnswer,
+ selectActiveQuestion,
+ selectActiveQuestionValidation,
+ selectAllQuestions,
+ setActiveQuestion,
} from "@/models/profilingQuestionsSlice";
import { useSelector } from "react-redux";
// import {motion} from "framer-motion"
const TextEntry = () => {
- const dispatch = useAppDispatch()
-
- const activeQuestion = useSelector(selectActiveQuestion);
- // const selectAnswer = useMemo(() => selectAnswerForQuestion(question), [question]);
- // const selectAnswer = useSelector(selectAnswerForQuestion(question));
- const metadata = activeQuestion?._metadata
- const validation = activeQuestion?._validation
- const bpuid = useAppSelector(state => state.app.bpuid)
-
- if (!metadata) return null
- if (!validation) return null
-
- const error = validation?.errors.length > 0
-
- const handleInputChange = (event: React.KeyboardEvent<HTMLInputElement>) => {
- if (!activeQuestion.question_id) return;
-
- const target = event.target as HTMLInputElement;
- dispatch(addAnswers({ questionId: activeQuestion.question_id!, answers: [target.value] as string[] }))
- };
-
- const handleKeyPress = (event: KeyboardEvent<HTMLInputElement>) => {
- if (!activeQuestion.question_id) return;
- if (!bpuid) return;
-
- if (event.key === 'Enter') {
- dispatch(saveAnswer({ questionId: activeQuestion.question_id!, bpuid: bpuid }))
- }
- };
-
- return (
- <div className="px-6 my-6">
- <input type="text"
- id="text-entry-input"
- aria-describedby=""
- // defaultValue={answer?.values.length ? answer?.values[0] : ""}
- onKeyUp={handleInputChange}
- onKeyDown={handleKeyPress} // Use onKeyDown to listen for the key press
- // title={error ? answer?.error_msg : ""}
- className={clsx(
- 'w-full border-1 rounded px-2 py-1',
- error ?
- 'border-red-500 focus-visible:ring-red-500' :
- 'border-blue-50'
- )}
- />
-
- {
- validation.errors.map(e => {
- return (
- <p className="text-sm text-red-100 my-2">{e.message}</p>
- )
- })
- }
- </div>
- )
-}
-
-
-export default function useKeyboardMode(
- rowModel: RowModel<UpkQuestionChoice>,
-) {
- // const [keyboardEnabled, setKeyboardEnabled] = useState(
- // localStorage.getItem(keyboardMode) === "enabled",
- // );
- const rowRefs = useRef<(HTMLTableRowElement | null)[]>([]);
-
- const dispatch = useAppDispatch()
- const activeQuestion = useSelector(selectActiveQuestion);
- const bpuid = useAppSelector(state => state.app.bpuid)
-
- const keyboardSelectionIdxRef = useRef(0);
-
- useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
-
- if (!activeQuestion) return;
- if (!bpuid) return;
-
- // if (!keyboardEnabled) {
- // return;
- // }
-
- const { key } = event;
- const totalRows = rowRefs.current.length;
- const prevIdx = keyboardSelectionIdxRef.current;
- let nextIdx = prevIdx;
-
- if (key === "ArrowDown") nextIdx = Math.min(prevIdx + 1, totalRows - 1);
- if (key === "ArrowUp") nextIdx = Math.max(prevIdx - 1, 0);
- if (key === " ") {
- const active = document.activeElement as HTMLElement | null;
-
- if (active?.tabIndex === 0) {
- return;
- } else {
- rowModel.rows[keyboardSelectionIdxRef.current].toggleSelected();
- }
- }
+ const dispatch = useAppDispatch();
+
+ const activeQuestion = useSelector(selectActiveQuestion);
+ // const selectAnswer = useMemo(() => selectAnswerForQuestion(question), [question]);
+ // const selectAnswer = useSelector(selectAnswerForQuestion(question));
+ const metadata = activeQuestion?._metadata;
+ const validation = activeQuestion?._validation;
+ const { data: user } = useGetMeQuery();
+
+ if (!metadata) return null;
+ if (!validation) return null;
+
+ const error = validation?.errors.length > 0;
+
+ const handleInputChange = (event: React.KeyboardEvent<HTMLInputElement>) => {
+ if (!activeQuestion.question_id) return;
+
+ const target = event.target as HTMLInputElement;
+ dispatch(
+ addAnswers({
+ questionId: activeQuestion.question_id!,
+ answers: [target.value] as string[],
+ }),
+ );
+ };
+
+ const handleKeyPress = (event: KeyboardEvent<HTMLInputElement>) => {
+ if (!activeQuestion.question_id) return;
+ if (!user?.product_user_id) return;
+
+ if (event.key === "Enter") {
+ dispatch(
+ saveAnswer({
+ questionId: activeQuestion.question_id!,
+ bpuid: user.product_user_id,
+ }),
+ );
+ }
+ };
+
+ return (
+ <div className="px-6 my-6">
+ <input
+ type="text"
+ id="text-entry-input"
+ aria-describedby=""
+ // defaultValue={answer?.values.length ? answer?.values[0] : ""}
+ onKeyUp={handleInputChange}
+ onKeyDown={handleKeyPress} // Use onKeyDown to listen for the key press
+ // title={error ? answer?.error_msg : ""}
+ className={clsx(
+ "w-full border-1 rounded px-2 py-1",
+ error
+ ? "border-red-500 focus-visible:ring-red-500"
+ : "border-blue-50",
+ )}
+ />
- if (event.key === 'Enter') {
- dispatch(saveAnswer({ questionId: activeQuestion.question_id!, bpuid: bpuid }))
- }
+ {validation.errors.map((e) => {
+ return <p className="text-sm text-red-100 my-2">{e.message}</p>;
+ })}
+ </div>
+ );
+};
+export default function useKeyboardMode(rowModel: RowModel<UpkQuestionChoice>) {
+ // const [keyboardEnabled, setKeyboardEnabled] = useState(
+ // localStorage.getItem(keyboardMode) === "enabled",
+ // );
+ const rowRefs = useRef<(HTMLTableRowElement | null)[]>([]);
- if (nextIdx !== prevIdx) {
+ const dispatch = useAppDispatch();
+ const activeQuestion = useSelector(selectActiveQuestion);
+ const { data: user } = useGetMeQuery();
- rowRefs.current[prevIdx]?.classList.remove("bg-blue-400");
- rowRefs.current[nextIdx]?.classList.add("bg-blue-400");
+ const keyboardSelectionIdxRef = useRef(0);
- rowRefs.current[nextIdx]?.scrollIntoView({
- behavior: "smooth",
- block: "center",
- });
- keyboardSelectionIdxRef.current = nextIdx;
- }
- };
+ useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (!activeQuestion) return;
+ if (!user?.product_user_id) return;
- // I really don't know, and I don't really care enough to make this
- // technically type'd correctly. - Max
+ // if (!keyboardEnabled) {
+ // return;
+ // }
- // @ts-ignore
- window.addEventListener("keydown", handleKeyDown);
- // @ts-ignore
- return () => window.removeEventListener("keydown", handleKeyDown);
+ const { key } = event;
+ const totalRows = rowRefs.current.length;
+ const prevIdx = keyboardSelectionIdxRef.current;
+ let nextIdx = prevIdx;
- }, [rowModel.rows]);
+ if (key === "ArrowDown") nextIdx = Math.min(prevIdx + 1, totalRows - 1);
+ if (key === "ArrowUp") nextIdx = Math.max(prevIdx - 1, 0);
+ if (key === " ") {
+ const active = document.activeElement as HTMLElement | null;
- return {
- // keyboardEnabled,
- // setKeyboardEnabled,
- rowRefs,
- keyboardSelectionIdxRef,
+ if (active?.tabIndex === 0) {
+ return;
+ } else {
+ rowModel.rows[keyboardSelectionIdxRef.current].toggleSelected();
+ }
+ }
+
+ if (event.key === "Enter") {
+ dispatch(
+ saveAnswer({
+ questionId: activeQuestion.question_id!,
+ bpuid: user.product_user_id,
+ }),
+ );
+ }
+
+ if (nextIdx !== prevIdx) {
+ rowRefs.current[prevIdx]?.classList.remove("bg-blue-400");
+ rowRefs.current[nextIdx]?.classList.add("bg-blue-400");
+
+ rowRefs.current[nextIdx]?.scrollIntoView({
+ behavior: "smooth",
+ block: "center",
+ });
+ keyboardSelectionIdxRef.current = nextIdx;
+ }
};
+
+ // I really don't know, and I don't really care enough to make this
+ // technically type'd correctly. - Max
+
+ // @ts-ignore
+ window.addEventListener("keydown", handleKeyDown);
+ // @ts-ignore
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [rowModel.rows]);
+
+ return {
+ // keyboardEnabled,
+ // setKeyboardEnabled,
+ rowRefs,
+ keyboardSelectionIdxRef,
+ };
}
const MultipleChoice = () => {
- const dispatch = useAppDispatch()
- const activeQuestion = useSelector(selectActiveQuestion);
-
- // const error: Boolean = answer?.error_msg.length > 0
- // console.log("Rendering MultipleChoice with answer:", answer, error)
-
- // TODO! Retrieve store values to use as the initial state for the table
- // This is useful for if they tab around before submitting the answer
- const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
- const [globalFilter, setGlobalFilter] = useState('');
-
- const handleRowSelectionChange = (updaterOrValue: RowSelectionState | ((old: RowSelectionState) => RowSelectionState)) => {
- setRowSelection((oldSelection) => {
- // Get the new selection state
- const newSelection = typeof updaterOrValue === 'function'
- ? updaterOrValue(oldSelection)
- : updaterOrValue;
-
- // Find which row was just selected/deselected
- const changedRowId = Object.keys(newSelection).find(
- key => newSelection[key] !== oldSelection[key]
- );
-
- if (!changedRowId) return newSelection;
-
- // Get the actual row data
- const row = table.getRow(changedRowId);
- const rowData = row.original; // Your row data object
-
- // Check if "None of the Above" was selected
- const normalized = rowData.choice_text.trim().toLowerCase();
- const isNoneOfTheAbove = (normalized === "none of the above") || (rowData.exclusive ?? false);
- if (isNoneOfTheAbove && newSelection[changedRowId]) {
- // Clear all other selections, keep only this one
- return { [changedRowId]: true };
- }
-
- // Check if a regular option was selected while "None of the Above" exists
- const noneOfTheAboveId = Object.keys(newSelection).find(id => {
- const r = table.getRow(id);
- const rowData = r.original as UpkQuestionChoice;
-
- const normalized = rowData.choice_text.trim().toLowerCase();
- const isNoneOfTheAbove = (normalized === "none of the above") || (rowData.exclusive ?? false);
-
- return isNoneOfTheAbove && newSelection[id];
- });
-
- if (noneOfTheAboveId && changedRowId !== noneOfTheAboveId) {
- // Remove "None of the Above" selection
- const { [noneOfTheAboveId]: _, ...rest } = newSelection;
- return rest;
- }
-
- return newSelection;
- });
- };
+ const dispatch = useAppDispatch();
+ const activeQuestion = useSelector(selectActiveQuestion);
+
+ // const error: Boolean = answer?.error_msg.length > 0
+ // console.log("Rendering MultipleChoice with answer:", answer, error)
+
+ // TODO! Retrieve store values to use as the initial state for the table
+ // This is useful for if they tab around before submitting the answer
+ const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
+ const [globalFilter, setGlobalFilter] = useState("");
+
+ const handleRowSelectionChange = (
+ updaterOrValue:
+ | RowSelectionState
+ | ((old: RowSelectionState) => RowSelectionState),
+ ) => {
+ setRowSelection((oldSelection) => {
+ // Get the new selection state
+ const newSelection =
+ typeof updaterOrValue === "function"
+ ? updaterOrValue(oldSelection)
+ : updaterOrValue;
+
+ // Find which row was just selected/deselected
+ const changedRowId = Object.keys(newSelection).find(
+ (key) => newSelection[key] !== oldSelection[key],
+ );
+
+ if (!changedRowId) return newSelection;
+
+ // Get the actual row data
+ const row = table.getRow(changedRowId);
+ const rowData = row.original; // Your row data object
+
+ // Check if "None of the Above" was selected
+ const normalized = rowData.choice_text.trim().toLowerCase();
+ const isNoneOfTheAbove =
+ normalized === "none of the above" || (rowData.exclusive ?? false);
+ if (isNoneOfTheAbove && newSelection[changedRowId]) {
+ // Clear all other selections, keep only this one
+ return { [changedRowId]: true };
+ }
+
+ // Check if a regular option was selected while "None of the Above" exists
+ const noneOfTheAboveId = Object.keys(newSelection).find((id) => {
+ const r = table.getRow(id);
+ const rowData = r.original as UpkQuestionChoice;
+
+ const normalized = rowData.choice_text.trim().toLowerCase();
+ const isNoneOfTheAbove =
+ normalized === "none of the above" || (rowData.exclusive ?? false);
+
+ return isNoneOfTheAbove && newSelection[id];
+ });
+
+ if (noneOfTheAboveId && changedRowId !== noneOfTheAboveId) {
+ // Remove "None of the Above" selection
+ const { [noneOfTheAboveId]: _, ...rest } = newSelection;
+ return rest;
+ }
+
+ return newSelection;
+ });
+ };
+
+ useEffect(() => {
+ if (!activeQuestion?.question_id) return;
+ // Run this anytime a rowSelection changes, to update
+ // the answer in the store
+ const selectedChoices = Object.keys(rowSelection);
+ dispatch(
+ addAnswers({
+ questionId: activeQuestion.question_id,
+ answers: selectedChoices,
+ }),
+ );
+ }, [rowSelection]);
+
+ // Define columns
+ const columnHelper = createColumnHelper<UpkQuestionChoice>();
+ const columns = [
+ columnHelper.display({
+ id: "select",
+ cell: ({ row }) => {
+ const canSelected = row.getCanSelect();
- useEffect(() => {
- if (!activeQuestion?.question_id) return;
- // Run this anytime a rowSelection changes, to update
- // the answer in the store
- const selectedChoices = Object.keys(rowSelection)
- dispatch(addAnswers({ questionId: activeQuestion.question_id, answers: selectedChoices }))
- }, [rowSelection])
-
- // Define columns
- const columnHelper = createColumnHelper<UpkQuestionChoice>()
- const columns = [
- columnHelper.display({
- id: 'select',
- cell: ({ row }) => {
- const canSelected = row.getCanSelect()
-
- return (
- <input
- type="checkbox"
- checked={row.getIsSelected()}
- disabled={!row.getCanSelect()}
- onChange={row.getToggleSelectedHandler()}
- className={`w-4 h-4 rounded-0 border-slate-300 cursor-pointer
+ return (
+ <input
+ type="checkbox"
+ checked={row.getIsSelected()}
+ disabled={!row.getCanSelect()}
+ onChange={row.getToggleSelectedHandler()}
+ className={`w-4 h-4 rounded-0 border-slate-300 cursor-pointer
focus:outline-none focus:border-blue-500 focus:ring-blue-500
- ${canSelected ? ' ' : 'hidden'}
+ ${canSelected ? " " : "hidden"}
`}
- />
- )
- },
- size: 20,
- meta: {
- align: 'center'
- }
- }),
-
- columnHelper.accessor("choice_text", {
- header: () => 'Choice Text',
- cell: (info) => {
- const text = info.getValue();
- const selected = info.row.getIsSelected()
- const canSelected = info.row.getCanSelect()
+ />
+ );
+ },
+ size: 20,
+ meta: {
+ align: "center",
+ },
+ }),
+
+ columnHelper.accessor("choice_text", {
+ header: () => "Choice Text",
+ cell: (info) => {
+ const text = info.getValue();
+ const selected = info.row.getIsSelected();
+ const canSelected = info.row.getCanSelect();
- return (
- <p className={`
+ return (
+ <p
+ className={`
w-max truncate
text-sm text-left pl-1
- ${selected ? 'font-bold' : 'font-medium'}
- ${canSelected ? 'text-blue-950' : 'text-blue-600'}
- `}>
- {text}
- </p>
- )
- },
- size: 380,
- meta: {
- align: 'left'
- }
- }),
- ]
-
- const table = useReactTable({
- 'data': activeQuestion!.choices ?? [],
- columns,
- getRowId: (row) => row.choice_id,
- state: {
- rowSelection,
- globalFilter,
- },
- // enableRowSelection: true,
- enableRowSelection: (row) => {
- // Allow deselection always, but limit new selections
- const currentSelectionCount = Object.keys(rowSelection).length;
- const isRowSelected = rowSelection[row.id];
-
- const max_selection = activeQuestion?.selector === "SA" ? 1 : activeQuestion?.choices?.length ?? 10
-
- // Allow if: row is already selected OR we haven't hit the limit
- return isRowSelected || currentSelectionCount < max_selection;
- },
- onRowSelectionChange: handleRowSelectionChange,
- onGlobalFilterChange: setGlobalFilter,
- getCoreRowModel: getCoreRowModel(),
- getSortedRowModel: getSortedRowModel(),
- getFilteredRowModel: getFilteredRowModel(),
- });
-
- const selectedCount = table.getSelectedRowModel().rows.length;
-
- //const { rowRefs, setKeyboardEnabled, keyboardSelectionIdxRef } = useKeyboardMode(table.getRowModel());
- const { rowRefs } = useKeyboardMode(table.getRowModel());
-
- return (
- <>
-
- {/* Controls */}
- <div className="py-1">
- <div className="flex flex-wrap gap-2">
-
- {/* Search */}
- <div className="flex-1">
- <input
- type="text"
- placeholder="Search choices..."
- value={globalFilter ?? ''}
- onChange={e => setGlobalFilter(e.target.value)}
- className="w-full px-4 py-1
+ ${selected ? "font-bold" : "font-medium"}
+ ${canSelected ? "text-blue-950" : "text-blue-600"}
+ `}
+ >
+ {text}
+ </p>
+ );
+ },
+ size: 380,
+ meta: {
+ align: "left",
+ },
+ }),
+ ];
+
+ const table = useReactTable({
+ data: activeQuestion!.choices ?? [],
+ columns,
+ getRowId: (row) => row.choice_id,
+ state: {
+ rowSelection,
+ globalFilter,
+ },
+ // enableRowSelection: true,
+ enableRowSelection: (row) => {
+ // Allow deselection always, but limit new selections
+ const currentSelectionCount = Object.keys(rowSelection).length;
+ const isRowSelected = rowSelection[row.id];
+
+ const max_selection =
+ activeQuestion?.selector === "SA"
+ ? 1
+ : (activeQuestion?.choices?.length ?? 10);
+
+ // Allow if: row is already selected OR we haven't hit the limit
+ return isRowSelected || currentSelectionCount < max_selection;
+ },
+ onRowSelectionChange: handleRowSelectionChange,
+ onGlobalFilterChange: setGlobalFilter,
+ getCoreRowModel: getCoreRowModel(),
+ getSortedRowModel: getSortedRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ });
+
+ const selectedCount = table.getSelectedRowModel().rows.length;
+
+ //const { rowRefs, setKeyboardEnabled, keyboardSelectionIdxRef } = useKeyboardMode(table.getRowModel());
+ const { rowRefs } = useKeyboardMode(table.getRowModel());
+
+ return (
+ <>
+ {/* Controls */}
+ <div className="py-1">
+ <div className="flex flex-wrap gap-2">
+ {/* Search */}
+ <div className="flex-1">
+ <input
+ type="text"
+ placeholder="Search choices..."
+ value={globalFilter ?? ""}
+ onChange={(e) => setGlobalFilter(e.target.value)}
+ className="w-full px-4 py-1
border border-blue-900 bg-blue-400 rounded
text-white text-sm
focus:outline-none focus:ring-2 focus:ring-indigo-500"
- />
- </div>
+ />
+ </div>
- {/* Selected Count */}
- {selectedCount > 0 && (
- <div className="flex items-center gap-2 px-2 py-1
+ {/* Selected Count */}
+ {selectedCount > 0 && (
+ <div
+ className="flex items-center gap-2 px-2 py-1
border border-blue-900 text-blue-700 rounded font-medium
text-[10px]
hover:cursor-pointer hover:bg-blue-800 hover:text-white
"
- onClick={() => setRowSelection({})}>
- <span>{selectedCount} selected</span>
- <button className="m-0 p-0 font-bold">✕</button>
- </div>
- )}
-
- </div>
+ onClick={() => setRowSelection({})}
+ >
+ <span>{selectedCount} selected</span>
+ <button className="m-0 p-0 font-bold">✕</button>
</div>
+ )}
+ </div>
+ </div>
- {/* Table */}
- <div className="border border-blue-200 rounded max-h-[400px] overflow-y-auto
+ {/* Table */}
+ <div
+ className="border border-blue-200 rounded max-h-[400px] overflow-y-auto
[&::-webkit-scrollbar]:h-[4px]
[&::-webkit-scrollbar]:w-1
[&::-webkit-scrollbar-track]:bg-blue-100
[&::-webkit-scrollbar-thumb]:bg-blue-300
- ">
- <table className="text-xs table-fixed border-collapse w-full">
- <tbody className="w-full">
- {table.getRowModel().rows.map((row, idx) => (
- <tr key={row.id}
- ref={(el) => {
- rowRefs.current[idx] = el;
- }}
- onClick={() => row.toggleSelected()}
- className={`cursor-pointer transition-colors w-full
- ${row.getIsSelected() ? 'bg-blue-600 ' : ' '
+ "
+ >
+ <table className="text-xs table-fixed border-collapse w-full">
+ <tbody className="w-full">
+ {table.getRowModel().rows.map((row, idx) => (
+ <tr
+ key={row.id}
+ ref={(el) => {
+ rowRefs.current[idx] = el;
+ }}
+ onClick={() => row.toggleSelected()}
+ className={`cursor-pointer transition-colors w-full
+ ${
+ row.getIsSelected() ? "bg-blue-600 " : " "
}`}
- >
-
- {row.getVisibleCells().map((cell) => {
- const align = cell.column.columnDef.meta?.align || 'left';
- const alignClass = align === 'center' ? 'text-center' :
- align === 'right' ? 'text-right' : 'text-left';
-
- return (
- <td key={cell.id}
- className={`py-2 ${alignClass}`}
- style={{
- width: `${cell.column.getSize()}px`,
- }}
- >
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
- </td>
- )
- })}
-
- </tr>
- ))}
- </tbody>
- </table>
- </div>
-
- {/* Empty State */}
- {table.getRowModel().rows.length === 0 && (
- <div className="p-12 text-center text-blue-50 font-bold">
- No items found matching your search
- </div>
- )}
+ >
+ {row.getVisibleCells().map((cell) => {
+ const align = cell.column.columnDef.meta?.align || "left";
+ const alignClass =
+ align === "center"
+ ? "text-center"
+ : align === "right"
+ ? "text-right"
+ : "text-left";
+
+ return (
+ <td
+ key={cell.id}
+ className={`py-2 ${alignClass}`}
+ style={{
+ width: `${cell.column.getSize()}px`,
+ }}
+ >
+ {flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext(),
+ )}
+ </td>
+ );
+ })}
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+
+ {/* Empty State */}
+ {table.getRowModel().rows.length === 0 && (
+ <div className="p-12 text-center text-blue-50 font-bold">
+ No items found matching your search
+ </div>
+ )}
- {/* Footer */}
- <div className="px-2 py-2 flex justify-between items-center
+ {/* Footer */}
+ <div
+ className="px-2 py-2 flex justify-between items-center
text-xs font-mono font-semibold text-blue-950
- ">
- <span>
- Showing {table.getRowModel().rows.length} of {activeQuestion?.choices?.length} choices
- </span>
- {selectedCount > 0 && (
- <span>
- {selectedCount} choice{selectedCount !== 1 ? 's' : ''} selected
- </span>
- )}
- </div>
-
- </>
- )
-
-}
+ "
+ >
+ <span>
+ Showing {table.getRowModel().rows.length} of{" "}
+ {activeQuestion?.choices?.length} choices
+ </span>
+ {selectedCount > 0 && (
+ <span>
+ {selectedCount} choice{selectedCount !== 1 ? "s" : ""} selected
+ </span>
+ )}
+ </div>
+ </>
+ );
+};
const ProfilingQuestionTitle = () => {
- const activeQuestion = useSelector(selectActiveQuestion);
- const question_active_tasks = activeQuestion?.importance?.task_count ?? 0
+ const activeQuestion = useSelector(selectActiveQuestion);
+ const question_active_tasks = activeQuestion?.importance?.task_count ?? 0;
- if (!activeQuestion) return null;
-
- let text = activeQuestion?.question_text
+ if (!activeQuestion) return null;
- if (activeQuestion.explanation_template && activeQuestion._validation?.isComplete && activeQuestion._metadata.answers.length == 1) {
- const template = activeQuestion.explanation_template;
- const pre_code = activeQuestion._metadata.answers[0];
+ let text = activeQuestion?.question_text;
- const choice = activeQuestion.choices?.find(c => c.choice_id === pre_code)
- const choice_text = choice ? choice.choice_text : "your answer"
+ if (
+ activeQuestion.explanation_template &&
+ activeQuestion._validation?.isComplete &&
+ activeQuestion._metadata.answers.length == 1
+ ) {
+ const template = activeQuestion.explanation_template;
+ const pre_code = activeQuestion._metadata.answers[0];
- text = template.replace("{answer}", choice_text)
- }
+ const choice = activeQuestion.choices?.find(
+ (c) => c.choice_id === pre_code,
+ );
+ const choice_text = choice ? choice.choice_text : "your answer";
+ text = template.replace("{answer}", choice_text);
+ }
- return (
- <div className="flex justify-between items-center px-2">
-
- <h3 className="text-left text-sm font-bold m-0 p-0
+ return (
+ <div className="flex justify-between items-center px-2">
+ <h3
+ className="text-left text-sm font-bold m-0 p-0
inline-block
- ">
- {text}
- </h3>
-
- <div className="max-w-[70px] text-center m-0 p-0">
- <h4 className="text-xs font-bold">
- {question_active_tasks.toLocaleString()}
- </h4>
- <h5 className="text-[10px]">
- Surveys use
- this question
- </h5>
- </div>
- </div>
- )
-}
+ "
+ >
+ {text}
+ </h3>
+
+ <div className="max-w-[70px] text-center m-0 p-0">
+ <h4 className="text-xs font-bold">
+ {question_active_tasks.toLocaleString()}
+ </h4>
+ <h5 className="text-[10px]">Surveys use this question</h5>
+ </div>
+ </div>
+ );
+};
const ProfilingQuestionSubmitButton = () => {
- const dispatch = useAppDispatch()
-
- const activeQuestion = useSelector(selectActiveQuestion);
- const activeQuestionValidation = useSelector(selectActiveQuestionValidation)
- const bpuid = useAppSelector(state => state.app.bpuid)
-
- const handleOnClick = () => {
- if (!activeQuestion) return
- if (!activeQuestionValidation?.isComplete) return
- if (!bpuid) return;
-
- dispatch(saveAnswer({ questionId: activeQuestion.question_id!, bpuid: bpuid }))
- }
-
- return (
- <button
- type="submit"
- className="cursor-pointer text-sm font-semibold
+ const dispatch = useAppDispatch();
+
+ const activeQuestion = useSelector(selectActiveQuestion);
+ const activeQuestionValidation = useSelector(selectActiveQuestionValidation);
+ const { data: user } = useGetMeQuery();
+
+ const handleOnClick = () => {
+ if (!activeQuestion) return;
+ if (!activeQuestionValidation?.isComplete) return;
+ if (!user?.product_user_id) return;
+
+ dispatch(
+ saveAnswer({
+ questionId: activeQuestion.question_id!,
+ bpuid: user.product_user_id,
+ }),
+ );
+ };
+
+ return (
+ <button
+ type="submit"
+ className="cursor-pointer text-sm font-semibold
bg-blue-700 text-white py-1 px-4 rounded
hover:bg-blue-900 min-w-[148px]
disabled:bg-blue-700 disabled:text-rose-300
disabled:cursor-not-allowed
"
- disabled={!activeQuestionValidation?.isComplete}
- onClick={handleOnClick}
- >
- Answer Question
- </button>
- )
-}
-
+ disabled={!activeQuestionValidation?.isComplete}
+ onClick={handleOnClick}
+ >
+ Answer Question
+ </button>
+ );
+};
export const ProfileQuestionFull = () => {
- const activeQuestion = useSelector(selectActiveQuestion);
-
- const renderContent = () => {
- if (!activeQuestion) return null;
- switch (activeQuestion.question_type) {
- case 'TE':
- return <TextEntry />
- case 'MC':
- return <MultipleChoice />
- default:
- return <MultipleChoice />
- }
- };
+ const activeQuestion = useSelector(selectActiveQuestion);
- if (!activeQuestion) return null
+ const renderContent = () => {
+ if (!activeQuestion) return null;
+ switch (activeQuestion.question_type) {
+ case "TE":
+ return <TextEntry />;
+ case "MC":
+ return <MultipleChoice />;
+ default:
+ return <MultipleChoice />;
+ }
+ };
- return (
- <>
- {/* {answer && answer.processing && (
+ if (!activeQuestion) return null;
+
+ return (
+ <>
+ {/* {answer && answer.processing && (
<motion.div
className="bg-gray-300"
initial={{ width: "0%" }}
@@ -540,104 +576,111 @@ export const ProfileQuestionFull = () => {
/>
)} */}
- {renderContent()}
- </>
- )
-}
+ {renderContent()}
+ </>
+ );
+};
const PaginationIcon: React.FC<{
- question: ProfileQuestion, idx: number,
+ question: ProfileQuestion;
+ idx: number;
}> = ({ question, idx }) => {
- const dispatch = useAppDispatch()
+ const dispatch = useAppDispatch();
- // const answers = useAppSelector(state => state.answers)
- const isActive = question._metadata?.isActive ?? false
- const completed = question._validation?.isComplete ?? false
+ // const answers = useAppSelector(state => state.answers)
+ const isActive = question._metadata?.isActive ?? false;
+ const completed = question._validation?.isComplete ?? false;
- const handleSetQuestion = (evt: MouseEvent<HTMLAnchorElement>) => {
- if (completed) {
- evt.preventDefault()
- } else {
- dispatch(setActiveQuestion(question.question_id!))
- }
+ const handleSetQuestion = (evt: MouseEvent<HTMLAnchorElement>) => {
+ if (completed) {
+ evt.preventDefault();
+ } else {
+ dispatch(setActiveQuestion(question.question_id!));
}
-
- return (
- <PaginationItem>
- <PaginationLink
- href="#"
- title={question.question_text}
- isActive={isActive}
- aria-disabled={!!completed}
-
- onClick={handleSetQuestion}
- className={clsx("cursor-pointer rounded border border-blue-300 text-blue-300 text-[10px] w-7 h-4",
- {
- "pointer-events-none cursor-not-allowed": completed,
- "bg-blue-800 border-blue-800": isActive,
- })}
- >
- {idx + 1}
- </PaginationLink>
- </PaginationItem>
- )
-}
+ };
+
+ return (
+ <PaginationItem>
+ <PaginationLink
+ href="#"
+ title={question.question_text}
+ isActive={isActive}
+ aria-disabled={!!completed}
+ onClick={handleSetQuestion}
+ className={clsx(
+ "cursor-pointer rounded border border-blue-300 text-blue-300 text-[10px] w-7 h-4",
+ {
+ "pointer-events-none cursor-not-allowed": completed,
+ "bg-blue-800 border-blue-800": isActive,
+ },
+ )}
+ >
+ {idx + 1}
+ </PaginationLink>
+ </PaginationItem>
+ );
+};
const ProfilingQuestionPagination = () => {
- const dispatch = useAppDispatch()
-
- const questions = useSelector(selectAllQuestions)
- const activeQuestion = useSelector(selectActiveQuestion)
-
- // All the variables needed for a sliding window
- const q_idx = questions.findIndex(q => q.question_id === activeQuestion!.question_id)
-
- const handleNextClick = () => {
- dispatch(goToNextQuestion());
- };
-
- const questionsWindow = (
- items: ProfileQuestion[], currentIndex: number, windowSize: number = 5
- ): ProfileQuestion[] => {
- const half: number = Math.floor(windowSize / 2)
- const total: number = items.length
- let start: number = currentIndex - half
- let end: number = currentIndex + half + 1
-
- if (start < 0) {
- end += Math.abs(start)
- start = 0
- }
-
- // Adjust if window goes past the end
- if (end > total) {
- const overflow: number = end - total
- start = Math.max(0, start - overflow)
- end = total
- }
+ const dispatch = useAppDispatch();
+
+ const questions = useSelector(selectAllQuestions);
+ const activeQuestion = useSelector(selectActiveQuestion);
+
+ // All the variables needed for a sliding window
+ const q_idx = questions.findIndex(
+ (q) => q.question_id === activeQuestion!.question_id,
+ );
+
+ const handleNextClick = () => {
+ dispatch(goToNextQuestion());
+ };
+
+ const questionsWindow = (
+ items: ProfileQuestion[],
+ currentIndex: number,
+ windowSize: number = 5,
+ ): ProfileQuestion[] => {
+ const half: number = Math.floor(windowSize / 2);
+ const total: number = items.length;
+ let start: number = currentIndex - half;
+ let end: number = currentIndex + half + 1;
+
+ if (start < 0) {
+ end += Math.abs(start);
+ start = 0;
+ }
- return items.slice(start, end)
+ // Adjust if window goes past the end
+ if (end > total) {
+ const overflow: number = end - total;
+ start = Math.max(0, start - overflow);
+ end = total;
}
- return (
- <Pagination>
- <PaginationContent>
- {
- questionsWindow(questions, q_idx).map(q => {
- return <PaginationIcon
- key={q.question_id}
- question={q}
- idx={questions.findIndex(qq => qq.question_id === q.question_id)}
- />
- })
- }
-
- <PaginationItem>
- <PaginationLink
- aria-label="Go to next page"
- size="default"
-
- className="rounded text-[10px] p-0 m-0
+ return items.slice(start, end);
+ };
+
+ return (
+ <Pagination>
+ <PaginationContent>
+ {questionsWindow(questions, q_idx).map((q) => {
+ return (
+ <PaginationIcon
+ key={q.question_id}
+ question={q}
+ idx={questions.findIndex(
+ (qq) => qq.question_id === q.question_id,
+ )}
+ />
+ );
+ })}
+
+ <PaginationItem>
+ <PaginationLink
+ aria-label="Go to next page"
+ size="default"
+ className="rounded text-[10px] p-0 m-0
text-blue-300
border border-blue-100 text-blue-100
hover:bg-blue-800 hover:border-blue-800 hover:text-white
@@ -645,115 +688,111 @@ const ProfilingQuestionPagination = () => {
h-4
w-13 sm:w-14
"
- onClick={handleNextClick}
- href="#"
- >
- <span className="block">Next</span>
- <ChevronRightIcon />
- </PaginationLink>
-
- </PaginationItem>
- </PaginationContent>
- </Pagination>
- )
-}
+ onClick={handleNextClick}
+ href="#"
+ >
+ <span className="block">Next</span>
+ <ChevronRightIcon />
+ </PaginationLink>
+ </PaginationItem>
+ </PaginationContent>
+ </Pagination>
+ );
+};
const ProfilingHeader = () => {
- const questions = useSelector(questionsSelectors.selectAll);
+ const questions = useSelector(questionsSelectors.selectAll);
- return (
- <h2 className="text-xs font-mono font-bold p-0 m-0">
- {questions.length} Profiling Questions
- </h2>
- )
-}
+ return (
+ <h2 className="text-xs font-mono font-bold p-0 m-0">
+ {questions.length} Profiling Questions
+ </h2>
+ );
+};
const ProfilingModalBody = () => {
- const activeQuestion = useSelector(selectActiveQuestion);
-
- if (!activeQuestion) {
- return (
- <div className="p-5">
- <h3 className="text-lg font-bold">No Profiling Questions Available</h3>
- <p className="my-0 text-sm text-gray-600">Please check back later.</p>
- </div>
- )
- }
+ const activeQuestion = useSelector(selectActiveQuestion);
+ if (!activeQuestion) {
return (
- <div className="relative flex flex-col">
- {/* <ProfilingQuestionPagination /> */}
-
- <div className="flex-shrink-0">
- <ProfilingQuestionTitle />
- </div>
-
- {/* Scrollable Content */}
- <div className="flex-1 p-1">
- <ProfileQuestionFull key={activeQuestion.question_id} />
- </div>
-
- {/* Sticky Footer */}
- <div className="flex-shrink-0 bg-blue-600 p-1 flex justify-between
- ">
- <div className="justify-start">
- <ProfilingQuestionPagination />
- </div>
- <div className="justify-end">
- <ProfilingQuestionSubmitButton />
- </div>
- </div>
-
+ <div className="p-5">
+ <h3 className="text-lg font-bold">No Profiling Questions Available</h3>
+ <p className="my-0 text-sm text-gray-600">Please check back later.</p>
+ </div>
+ );
+ }
+
+ return (
+ <div className="relative flex flex-col">
+ {/* <ProfilingQuestionPagination /> */}
+
+ <div className="flex-shrink-0">
+ <ProfilingQuestionTitle />
+ </div>
+
+ {/* Scrollable Content */}
+ <div className="flex-1 p-1">
+ <ProfileQuestionFull key={activeQuestion.question_id} />
+ </div>
+
+ {/* Sticky Footer */}
+ <div
+ className="flex-shrink-0 bg-blue-600 p-1 flex justify-between
+ "
+ >
+ <div className="justify-start">
+ <ProfilingQuestionPagination />
</div>
- )
-}
+ <div className="justify-end">
+ <ProfilingQuestionSubmitButton />
+ </div>
+ </div>
+ </div>
+ );
+};
const Profiling = () => {
- /* This is the main UI for any User Profiling (before entering a task). It's
+ /* This is the main UI for any User Profiling (before entering a task). It's
primary window and position should be dedictated by it's parent so this
can be positioned as a window or a sidebar as needed.
*/
- const [showProfiling, setShowProfiling] = useState(false);
+ const [showProfiling, setShowProfiling] = useState(false);
- const dispatch = useAppDispatch()
- const bpuid = useAppSelector(state => state.app.bpuid)
+ const dispatch = useAppDispatch();
+ const { data: user } = useGetMeQuery();
- useEffect(() => {
- if (!bpuid) return;
- dispatch(fetchNewQuestions(bpuid));
- }, [bpid, bpuid])
+ useEffect(() => {
+ if (!user?.product_user_id) return;
+ dispatch(fetchNewQuestions(user.product_user_id));
+ }, [bpid, user?.product_user_id]);
- if (!bpuid) return null;
+ if (!user?.product_user_id) return null;
- return (
- <div className={clsx(
- "fixed rounded bg-blue-500 text-white shadow-lg z-60 \
+ return (
+ <div
+ className={clsx(
+ "fixed rounded bg-blue-500 text-white shadow-lg z-60 \
bottom-1 sm:bottom-6 \
left-1 sm:left-2",
- showProfiling ? "w-[98vw] sm:w-[400px]" : "w-[220px]"
- )}
- >
-
- <div className="bg-blue-600 rounded border-white-300
+ showProfiling ? "w-[98vw] sm:w-[400px]" : "w-[220px]",
+ )}
+ >
+ <div
+ className="bg-blue-600 rounded border-white-300
cursor-pointer py-1 px-4
hover:bg-blue-700 transition-colors duration-200"
- onClick={() => setShowProfiling(!showProfiling)}
- >
- <ProfilingHeader />
-
- <h4 className="text-[10px] text-center italic text-white-300 py-0">
- (Click to {showProfiling ? 'hide' : 'show'})
- </h4>
- </div>
-
- {showProfiling && (
- <ProfilingModalBody />
- )}
-
- </div>
- )
-}
-
-export {
- Profiling
+ onClick={() => setShowProfiling(!showProfiling)}
+ >
+ <ProfilingHeader />
+
+ <h4 className="text-[10px] text-center italic text-white-300 py-0">
+ (Click to {showProfiling ? "hide" : "show"})
+ </h4>
+ </div>
+
+ {showProfiling && <ProfilingModalBody />}
+ </div>
+ );
};
+
+export { Profiling };
diff --git a/jb-ui/src/components/Redemption.tsx b/jb-ui/src/components/Redemption.tsx
new file mode 100644
index 0000000..1d76f17
--- /dev/null
+++ b/jb-ui/src/components/Redemption.tsx
@@ -0,0 +1,61 @@
+import { clsx } from "clsx";
+import { useState } from "react";
+// import { useSelector } from "react-redux";
+// import { cashoutMethodsSelectors } from "@/models/cashoutMethodsSlice";
+
+const RedemptionHeader = () => {
+ // const cashout_methods = useSelector(cashoutMethodsSelectors.selectAll);
+
+ return (
+ <>
+ <h2 className="text-xs font-mono font-bold p-0 m-0">
+ {/* {cashout_methods.length} Redemption Methods */}
+ 30+ Redemption Methods
+ </h2>
+ </>
+ );
+};
+
+const RedemptionModalBody = () => {
+ return (
+ <div className="grid grid-cols-[auto_1fr] text-xs">
+ <div className="label text-center p-2">
+ Paypal, Visa, Giftcards will be available. Finishing processing the
+ transfer from Amazon.
+ </div>
+ </div>
+ );
+};
+
+const Redemption = () => {
+ const [showRedemption, setShowRedemption] = useState(false);
+
+ return (
+ <div
+ className={clsx(
+ "fixed rounded bg-blue-500 text-white shadow-lg z-60 \
+ top-1 sm:top-6 \
+ right-1 sm:right-2",
+ showRedemption ? "w-[98vw] sm:w-[400px]" : "w-[220px]",
+ )}
+ >
+ <div
+ className="bg-blue-600 rounded border-white-300
+ cursor-pointer py-1 px-4
+ hover:bg-blue-700 transition-colors duration-200"
+ onClick={() => setShowRedemption(!showRedemption)}
+ >
+ <RedemptionHeader />
+
+ <h4 className="text-[10px] text-center italic text-white-300 py-0">
+ {/* (Click to {showRedemption ? "hide" : "show"}) */}
+ Details within 24hr.
+ </h4>
+ </div>
+
+ {showRedemption && <RedemptionModalBody />}
+ </div>
+ );
+};
+
+export default Redemption;
diff --git a/jb-ui/src/components/Wallet.tsx b/jb-ui/src/components/Wallet.tsx
index e4fc694..819eff7 100644
--- a/jb-ui/src/components/Wallet.tsx
+++ b/jb-ui/src/components/Wallet.tsx
@@ -1,464 +1,498 @@
import {
- UserLedgerTransactionsResponse,
- UserLedgerTransactionsResponseTransactionsInner,
- WalletApi
+ UserLedgerTransactionsResponse,
+ UserLedgerTransactionsResponseTransactionsInner,
+ WalletApi,
} from "@/api_fsb";
+import { useGetMeQuery } from "@/models/authAPI";
import { useAppDispatch, useAppSelector } from "@/hooks";
-import { bpid, formatCentsToUSD, } from "@/lib/utils";
+import { bpid, formatCentsToUSD } from "@/lib/utils";
import {
- setTxPagination, setTxTotalItems, setTxTotalPages,
- setUserLedgerSummary,
- setUserLedgerTxs
+ setTxPagination,
+ setTxTotalItems,
+ setTxTotalPages,
+ setUserLedgerSummary,
+ setUserLedgerTxs,
} from "@/models/appSlice";
import {
- RowData, createColumnHelper, flexRender, getCoreRowModel,
- useReactTable
+ RowData,
+ createColumnHelper,
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
} from "@tanstack/react-table";
import moment from "moment";
import { useEffect, useState } from "react";
-declare module '@tanstack/react-table' {
- interface ColumnMeta<TData extends RowData, TValue> {
- align?: 'left' | 'center' | 'right';
- }
+declare module "@tanstack/react-table" {
+ interface ColumnMeta<TData extends RowData, TValue> {
+ align?: "left" | "center" | "right";
+ }
}
// Function to calculate background color based on balance
const getBackgroundColor = (balance: number | undefined): string => {
- if (balance === undefined || balance === null) return 'bg-blue-600';
-
- if (balance > 0) {
- return 'bg-blue-600';
- } else if (balance <= -100) {
- return 'bg-red-600';
- } else {
- // Interpolate between blue and red for values between 0 and -100
- // progress goes from 0 (at balance = 0) to 1 (at balance = -100)
- const progress = Math.abs(balance) / 100;
-
- // Blue RGB: (37, 99, 235) - Tailwind blue-600
- // Red RGB: (220, 38, 38) - Tailwind red-600
- const r = Math.round(37 + (220 - 37) * progress);
- const g = Math.round(99 + (38 - 99) * progress);
- const b = Math.round(235 + (38 - 235) * progress);
-
- return `rgb(${r}, ${g}, ${b})`;
- }
+ if (balance === undefined || balance === null) return "bg-blue-600";
+
+ if (balance > 0) {
+ return "bg-blue-600";
+ } else if (balance <= -100) {
+ return "bg-red-600";
+ } else {
+ // Interpolate between blue and red for values between 0 and -100
+ // progress goes from 0 (at balance = 0) to 1 (at balance = -100)
+ const progress = Math.abs(balance) / 100;
+
+ // Blue RGB: (37, 99, 235) - Tailwind blue-600
+ // Red RGB: (220, 38, 38) - Tailwind red-600
+ const r = Math.round(37 + (220 - 37) * progress);
+ const g = Math.round(99 + (38 - 99) * progress);
+ const b = Math.round(235 + (38 - 235) * progress);
+
+ return `rgb(${r}, ${g}, ${b})`;
+ }
};
-
const WalletHeader = () => {
- const amount = useAppSelector(state => state.app.userWalletBalance)?.amount ?? 0
-
- const bgStyle = typeof getBackgroundColor(amount) === 'string' &&
- getBackgroundColor(amount).startsWith('bg-')
- ? {}
- : { backgroundColor: getBackgroundColor(amount) };
-
- const bgClass = typeof getBackgroundColor(amount) === 'string' &&
- getBackgroundColor(amount).startsWith('bg-')
- ? getBackgroundColor(amount)
- : '';
-
- return (
- <div className={`w-full py-1 px-1 text-white rounded ${bgClass}`}
- style={bgStyle}
- >
- <h2 className="text-xs font-semibold flex justify-between items-center">
- <span className="text-left">User Wallet:</span>
-
- {amount >= 0 ? (
- <span className='text-emerald-50'>
- {`${formatCentsToUSD(Math.abs(amount))}`}
- </span>
- ) : (
- <span className='text-rose-50'>
- {`(${formatCentsToUSD(Math.abs(amount))})`}
- </span>
- )}
-
- </h2>
- </div>
- )
+ const amount =
+ useAppSelector((state) => state.app.userDisplayedWalletBalance?.amount) ??
+ 0;
+
+ const amount_string =
+ useAppSelector(
+ (state) => state.app.userDisplayedWalletBalance?.amount_string,
+ ) ?? "$0.00";
+
+ const bgStyle =
+ typeof getBackgroundColor(amount) === "string" &&
+ getBackgroundColor(amount).startsWith("bg-")
+ ? {}
+ : { backgroundColor: getBackgroundColor(amount) };
+
+ const bgClass =
+ typeof getBackgroundColor(amount) === "string" &&
+ getBackgroundColor(amount).startsWith("bg-")
+ ? getBackgroundColor(amount)
+ : "";
+
+ return (
+ <div
+ className={`w-full py-1 px-1 text-white rounded ${bgClass}`}
+ style={bgStyle}
+ >
+ <h2 className="text-xs font-semibold flex justify-between items-center">
+ <span className="text-left">User Wallet:</span>
+
+ {amount >= 0 ? (
+ <span className="text-emerald-50">{`${amount_string}`}</span>
+ ) : (
+ <span className="text-rose-50">{`(${amount_string})`}</span>
+ )}
+ </h2>
+ </div>
+ );
};
const WalletSummary = () => {
- const summary = useAppSelector(state => state.app.userLedgerSummary)
-
- const survey_completes = summary?.bp_payment?.entry_count ?? 0
- const survey_completes_f = (survey_completes ?? 0).toLocaleString('en-US')
-
- const survey_adjustments = summary?.bp_adjustment?.entry_count ?? 0
- const survey_adjustments_f = (survey_adjustments ?? 0).toLocaleString('en-US')
-
- const min_payout: number = summary?.bp_payment?.min_amount ?? 0
- const max_payout: number = summary?.bp_payment?.max_amount ?? 0
- const adj_total: number = summary?.bp_adjustment?.total_amount ?? 0
- const user_payments_total: number = (summary?.user_payout_request?.total_amount ?? 0) * -1
-
- return (
- <div className="grid grid-cols-[auto_1fr] text-xs">
- <div className="label text-left">Completes:</div>
- <div className="value text-right">{survey_completes_f} surveys</div>
-
- <div className="label text-left">Avg Payouts:</div>
- <div className="value text-right">{formatCentsToUSD(min_payout)} – {formatCentsToUSD(max_payout)}</div>
-
- <div className="label text-left">Survey Adjustments:</div>
- <div className="value text-right">{survey_adjustments_f}</div>
-
- <div className="label text-left">Adjustment Amount:</div>
- <div className="value text-right">
- {adj_total >= 0 ? (
- <span className='text-emerald-300'>
- {`${formatCentsToUSD(adj_total)}`}
- </span>
- ) : (
- <span className='text-rose-300'>
- {`(${formatCentsToUSD(Math.abs(adj_total))})`}
- </span>
- )}
- </div>
-
- <div className="label text-left">User Payments:</div>
- <div className="value text-right">
- {user_payments_total >= 0 ? (
- <span className='text-emerald-300'>
- {`${formatCentsToUSD(user_payments_total)}`}
- </span>
- ) : (
- <span className='text-rose-300'>
- {`(${formatCentsToUSD(Math.abs(user_payments_total))})`}
- </span>
- )}
-
- </div>
- </div >
- )
+ const summary = useAppSelector((state) => state.app.userLedgerSummary);
+
+ const userWallet = useAppSelector((state) => state.app.userWallet);
+
+ userWallet;
+
+ const survey_completes = summary?.bp_payment?.entry_count ?? 0;
+ const survey_completes_f = (survey_completes ?? 0).toLocaleString("en-US");
+
+ const survey_adjustments = summary?.bp_adjustment?.entry_count ?? 0;
+ const survey_adjustments_f = (survey_adjustments ?? 0).toLocaleString(
+ "en-US",
+ );
+
+ const min_payout: number = summary?.bp_payment?.min_amount ?? 0;
+ const max_payout: number = summary?.bp_payment?.max_amount ?? 0;
+ const adj_total: number = summary?.bp_adjustment?.total_amount ?? 0;
+ const user_payments_total: number =
+ (summary?.user_payout_request?.total_amount ?? 0) * -1;
+
+ return (
+ <div className="grid grid-cols-[auto_1fr] text-xs">
+ <div className="label text-left">Completes:</div>
+ <div className="value text-right">{survey_completes_f} surveys</div>
+
+ <div className="label text-left">Avg Payouts:</div>
+ <div className="value text-right">
+ {formatCentsToUSD(min_payout)} – {formatCentsToUSD(max_payout)}
+ </div>
+
+ <div className="label text-left">Survey Adjustments:</div>
+ <div className="value text-right">{survey_adjustments_f}</div>
+
+ <div className="label text-left">Adjustment Amount:</div>
+ <div className="value text-right">
+ {adj_total >= 0 ? (
+ <span className="text-emerald-300">
+ {`${formatCentsToUSD(adj_total)}`}
+ </span>
+ ) : (
+ <span className="text-rose-300">
+ {`(${formatCentsToUSD(Math.abs(adj_total))})`}
+ </span>
+ )}
+ </div>
+
+ <div className="label text-left">User Payments:</div>
+ <div className="value text-right">
+ {user_payments_total >= 0 ? (
+ <span className="text-emerald-300">
+ {`${formatCentsToUSD(user_payments_total)}`}
+ </span>
+ ) : (
+ <span className="text-rose-300">
+ {`(${formatCentsToUSD(Math.abs(user_payments_total))})`}
+ </span>
+ )}
+ </div>
+ </div>
+ );
};
const WalletTransactionsHeader = () => {
- const tx_cnt = useAppSelector(state => state.app.txTotalItems)
- const txt_cnt_f = (tx_cnt ?? 0).toLocaleString('en-US')
-
- const [showTx, setShowTx] = useState(false);
-
- return (
- <div className="w-full bg-blue-600 text-white rounded text-left">
- <div className="hover:cursor-pointer hover:bg-blue-700 transition-colors duration-200"
- onClick={() => setShowTx(!showTx)}>
-
- <h2 className="text-xs font-semibold rounded flex justify-between
+ const tx_cnt = useAppSelector((state) => state.app.txTotalItems);
+ const txt_cnt_f = (tx_cnt ?? 0).toLocaleString("en-US");
+
+ const [showTx, setShowTx] = useState(false);
+
+ return (
+ <div className="w-full bg-blue-600 text-white rounded text-left">
+ <div
+ className="hover:cursor-pointer hover:bg-blue-700 transition-colors duration-200"
+ onClick={() => setShowTx(!showTx)}
+ >
+ <h2
+ className="text-xs font-semibold rounded flex justify-between
py-1 px-1"
- onClick={() => setShowTx(!showTx)}
- >
- <span>Total Transactions:</span> <span>{txt_cnt_f}</span>
- </h2>
-
- <h4 className="text-[10px] text-center italic text-blue-300 py-1"
- onClick={() => setShowTx(!showTx)}
- >
- (Click to {showTx ? 'hide' : 'show'})
- </h4>
-
- </div>
-
- {showTx && (
- <>
- <WalletTransactions />
- </>
- )}
+ onClick={() => setShowTx(!showTx)}
+ >
+ <span>Total Transactions:</span> <span>{txt_cnt_f}</span>
+ </h2>
- </div>
- )
+ <h4
+ className="text-[10px] text-center italic text-blue-300 py-1"
+ onClick={() => setShowTx(!showTx)}
+ >
+ (Click to {showTx ? "hide" : "show"})
+ </h4>
+ </div>
+
+ {showTx && (
+ <>
+ <WalletTransactions />
+ </>
+ )}
+ </div>
+ );
};
-
const WalletTransactions = () => {
- const dispatch = useAppDispatch()
- const bpuid = useAppSelector(state => state.app.bpuid)
- const userLedgerTxs = useAppSelector(state => state.app.userLedgerTxs);
-
- const txPagination = useAppSelector(state => state.app.txPagination);
- const txTotalPages = useAppSelector(state => state.app.txTotalPages);
-
- useEffect(() => {
- if (!bpuid) return;
-
- new WalletApi().getUserTransactionHistoryProductIdTransactionHistoryGet(
- bpid, // productId
- bpuid, // bpuid
- undefined, // createdAfter
- undefined, // createdBefore
- "-created", // orderBy
- txPagination.pageIndex + 1, // page
- txPagination.pageSize // pageSize
- ).then(res => {
- const response = res.data as UserLedgerTransactionsResponse;
- console.log("Wallet: fetched user ledger", response);
- dispatch(setUserLedgerSummary(response.summary));
-
- dispatch(setUserLedgerTxs(response.transactions ?? []))
- dispatch(setTxTotalItems(response.total!))
- dispatch(setTxTotalPages(response.pages!))
- });
-
- }, [bpuid, txPagination.pageIndex, txPagination.pageSize]);
-
- const columnHelper = createColumnHelper<UserLedgerTransactionsResponseTransactionsInner>()
- const columns = [
- columnHelper.accessor('created', {
- header: () => 'Date',
- cell: (info) => moment(info.getValue()).format('M/D/YY H:mm'),
- size: 110,
- meta: {
- align: 'left'
- }
- }),
- columnHelper.accessor('description', {
- header: () => 'Type',
- cell: props => {
- const desc = props.getValue();
- switch (desc) {
- case 'Task Complete':
- return 'Survey 🎉';
- case 'Task Adjustment':
- return 'Reject ⚠️';
- case 'Compensation Bonus':
- return 'Bonus 🎁';
- case 'HIT Bonus':
- return 'Bonus';
- case 'HIT Reward':
- return 'Assignment';
- default:
- return desc;
- }
- },
- size: 80,
- meta: {
- align: 'left'
- }
- }),
- columnHelper.accessor('amount', {
- header: () => 'Amount',
- cell: (props) => {
- const val = props.renderValue() as number;
- const isPositive = val >= 0;
- const emoji = isPositive ? "⬆\uFE0E" : "⬇\uFE0E";
- const colorClass = isPositive ? 'font-variant-emoji-text text-emerald-300' : 'font-variant-emoji-text text-rose-300';
+ const dispatch = useAppDispatch();
+ const { data: user } = useGetMeQuery();
+ const userLedgerTxs = useAppSelector((state) => state.app.userLedgerTxs);
+
+ const txPagination = useAppSelector((state) => state.app.txPagination);
+ const txTotalPages = useAppSelector((state) => state.app.txTotalPages);
+
+ useEffect(() => {
+ if (!user?.product_user_id) return;
+
+ new WalletApi()
+ .getUserTransactionHistoryProductIdTransactionHistoryGet(
+ bpid, // productId
+ user.product_user_id,
+ undefined, // createdAfter
+ undefined, // createdBefore
+ "-created", // orderBy
+ txPagination.pageIndex + 1, // page
+ txPagination.pageSize, // pageSize
+ )
+ .then((res) => {
+ const response = res.data as UserLedgerTransactionsResponse;
+ console.log("Wallet: fetched user ledger", response);
+ dispatch(setUserLedgerSummary(response.summary));
+
+ dispatch(setUserLedgerTxs(response.transactions ?? []));
+ dispatch(setTxTotalItems(response.total!));
+ dispatch(setTxTotalPages(response.pages!));
+ });
+ }, [user?.product_user_id, txPagination.pageIndex, txPagination.pageSize]);
+
+ const columnHelper =
+ createColumnHelper<UserLedgerTransactionsResponseTransactionsInner>();
+ const columns = [
+ columnHelper.accessor("created", {
+ header: () => "Date",
+ cell: (info) => moment(info.getValue()).format("M/D/YY H:mm"),
+ size: 110,
+ meta: {
+ align: "left",
+ },
+ }),
+ columnHelper.accessor("description", {
+ header: () => "Type",
+ cell: (props) => {
+ const desc = props.getValue();
+ switch (desc) {
+ case "Task Complete":
+ return "Survey 🎉";
+ case "Task Adjustment":
+ return "Reject ⚠️";
+ case "Compensation Bonus":
+ return "Bonus 🎁";
+ case "HIT Bonus":
+ return "Bonus";
+ case "HIT Reward":
+ return "Assignment";
+ default:
+ return desc;
+ }
+ },
+ size: 80,
+ meta: {
+ align: "left",
+ },
+ }),
+ columnHelper.accessor("amount", {
+ header: () => "Amount",
+ cell: (props) => {
+ const val = props.renderValue() as number;
+ const isPositive = val >= 0;
+ const emoji = isPositive ? "⬆\uFE0E" : "⬇\uFE0E";
+ const colorClass = isPositive
+ ? "font-variant-emoji-text text-emerald-300"
+ : "font-variant-emoji-text text-rose-300";
+
+ return (
+ <span className={colorClass}>
+ {`${emoji} ${formatCentsToUSD(Math.abs(val))}`}
+ </span>
+ );
+ },
+ size: 70,
+ meta: {
+ align: "center",
+ },
+ }),
+ columnHelper.accessor("balance_after", {
+ header: () => "Balance",
+ cell: (props) => {
+ const val = props.renderValue() as number;
+ const isPositive = val >= 0;
+ const colorClass = isPositive ? "text-emerald-300" : "text-rose-300";
+
+ return (
+ <>
+ {isPositive ? (
+ <span className={colorClass}>
+ {`${formatCentsToUSD(Math.abs(val))}`}
+ </span>
+ ) : (
+ <span className={colorClass}>
+ {`(${formatCentsToUSD(Math.abs(val))})`}
+ </span>
+ )}
+ </>
+ );
+ },
+ size: 70,
+ meta: {
+ align: "center",
+ },
+ }),
+ ];
+
+ const table = useReactTable({
+ data: userLedgerTxs,
+ columns: columns,
+ getCoreRowModel: getCoreRowModel(),
+ manualPagination: true,
+ pageCount: txTotalPages,
+ onPaginationChange: (updater) => {
+ dispatch(
+ setTxPagination(
+ typeof updater === "function" ? updater(txPagination) : updater,
+ ),
+ );
+ },
+ state: {
+ pagination: txPagination,
+ },
+ });
+
+ return (
+ <div className="w-full border-t-1 border-blue-800 p-2">
+ <table className="text-xs table-fixed border-collapse">
+ <thead className="font-bold">
+ {table.getHeaderGroups().map((headerGroup) => (
+ <tr key={headerGroup.id}>
+ {headerGroup.headers.map((header) => {
+ const align = header.column.columnDef.meta?.align || "left";
+ const alignClass =
+ align === "center"
+ ? "text-center"
+ : align === "right"
+ ? "text-right"
+ : "text-left";
return (
- <span className={colorClass}>
- {`${emoji} ${formatCentsToUSD(Math.abs(val))}`}
- </span>
- )
- },
- size: 70,
- meta: {
- align: 'center'
- }
- }),
- columnHelper.accessor('balance_after', {
- header: () => 'Balance',
- cell: (props) => {
- const val = props.renderValue() as number;
- const isPositive = val >= 0;
- const colorClass = isPositive ? 'text-emerald-300' : 'text-rose-300';
+ <th
+ key={header.id}
+ className={`p-0 m-0 ${alignClass}`}
+ style={{
+ width: `${header.column.getSize()}px`,
+ }}
+ >
+ {flexRender(
+ header.column.columnDef.header,
+ header.getContext(),
+ )}
+ </th>
+ );
+ })}
+ </tr>
+ ))}
+ </thead>
+ <tbody>
+ {table.getRowModel().rows.map((row) => (
+ <tr key={row.id}>
+ {row.getVisibleCells().map((cell) => {
+ const align = cell.column.columnDef.meta?.align || "left";
+ const alignClass =
+ align === "center"
+ ? "text-center"
+ : align === "right"
+ ? "text-right"
+ : "text-left";
return (
- <>
- {isPositive ? (
- <span className={colorClass}>
- {`${formatCentsToUSD(Math.abs(val))}`}
- </span>
- ) : (
- <span className={colorClass}>
- {`(${formatCentsToUSD(Math.abs(val))})`}
- </span>
- )}
- </>
- )
- },
- size: 70,
- meta: {
- align: 'center'
- }
- }),
- ]
-
- const table = useReactTable({
- 'data': userLedgerTxs,
- 'columns': columns,
- getCoreRowModel: getCoreRowModel(),
- manualPagination: true,
- pageCount: txTotalPages,
- onPaginationChange: (updater) => {
- dispatch(setTxPagination(
- typeof updater === 'function' ? updater(txPagination) : updater
- ));
- },
- state: {
- pagination: txPagination,
- },
- });
-
- return (
- <div className="w-full border-t-1 border-blue-800 p-2">
- <table className="text-xs table-fixed border-collapse">
- <thead className="font-bold">
- {table.getHeaderGroups().map((headerGroup) => (
-
- <tr key={headerGroup.id}>
- {headerGroup.headers.map((header) => {
- const align = header.column.columnDef.meta?.align || 'left';
- const alignClass = align === 'center' ? 'text-center' : align === 'right' ? 'text-right' : 'text-left';
-
- return (
- <th
- key={header.id}
- className={`p-0 m-0 ${alignClass}`}
- style={{
- width: `${header.column.getSize()}px`,
- }}
- >
- {flexRender(
- header.column.columnDef.header,
- header.getContext(),
- )}
- </th>
- )
- })}
- </tr>
- ))}
- </thead>
- <tbody>
- {table.getRowModel().rows.map((row) => (
- <tr key={row.id}>
- {row.getVisibleCells().map((cell) => {
- const align = cell.column.columnDef.meta?.align || 'left';
- const alignClass = align === 'center' ? 'text-center' :
- align === 'right' ? 'text-right' : 'text-left';
-
- return (
- <td key={cell.id}
- className={`p-0 ${alignClass}`}
- style={{
- width: `${cell.column.getSize()}px`,
- }}
- >
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
- </td>
- )
- })}
- </tr>
- ))}
- </tbody>
-
- <tfoot>
- <tr>
- <td colSpan={columns.length} className="p-2">
- <div className="flex items-center justify-between text-xs">
-
- {/* Page info */}
- <div className="text-blue-50">
- Page {table.getState().pagination.pageIndex + 1} of{' '}
- {table.getPageCount()}
- </div>
-
- {/* Navigation buttons */}
- <div className="flex gap-8 text-xs">
- <button
- onClick={() => table.previousPage()}
- disabled={!table.getCanPreviousPage()}
- className="px-3 py-1 border border-blue-200 rounded
+ <td
+ key={cell.id}
+ className={`p-0 ${alignClass}`}
+ style={{
+ width: `${cell.column.getSize()}px`,
+ }}
+ >
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+ </td>
+ );
+ })}
+ </tr>
+ ))}
+ </tbody>
+
+ <tfoot>
+ <tr>
+ <td colSpan={columns.length} className="p-2">
+ <div className="flex items-center justify-between text-xs">
+ {/* Page info */}
+ <div className="text-blue-50">
+ Page {table.getState().pagination.pageIndex + 1} of{" "}
+ {table.getPageCount()}
+ </div>
+
+ {/* Navigation buttons */}
+ <div className="flex gap-8 text-xs">
+ <button
+ onClick={() => table.previousPage()}
+ disabled={!table.getCanPreviousPage()}
+ className="px-3 py-1 border border-blue-200 rounded
font-variant-emoji-text
hover:cursor-pointer hover:bg-blue-700
disabled:opacity-50 disabled:cursor-not-allowed"
- >
- {'⬅\uFE0E'}
- </button>
- <button
- onClick={() => table.nextPage()}
- disabled={!table.getCanNextPage()}
- className="px-3 py-1 border border-blue-200 rounded
+ >
+ {"⬅\uFE0E"}
+ </button>
+ <button
+ onClick={() => table.nextPage()}
+ disabled={!table.getCanNextPage()}
+ className="px-3 py-1 border border-blue-200 rounded
font-variant-emoji-text
hover:cursor-pointer hover:bg-blue-700
disabled:opacity-50 disabled:cursor-not-allowed"
- >
- {'⮕\uFE0E'}
- </button>
- </div>
-
- {/* Page size selector */}
- <select
- value={table.getState().pagination.pageSize}
- onChange={e => table.setPageSize(Number(e.target.value))}
- className="px-2 py-1 border border-blue-200 rounded
+ >
+ {"⮕\uFE0E"}
+ </button>
+ </div>
+
+ {/* Page size selector */}
+ <select
+ value={table.getState().pagination.pageSize}
+ onChange={(e) => table.setPageSize(Number(e.target.value))}
+ className="px-2 py-1 border border-blue-200 rounded
hover:cursor-pointer hover:bg-blue-700"
- >
- {[10, 20, 30, 40].map(pageSize => (
- <option key={pageSize} value={pageSize}>
- Show {pageSize}
- </option>
- ))}
- </select>
- </div>
- </td>
- </tr>
- </tfoot>
-
- </table>
- </div>
- )
+ >
+ {[10, 20, 30, 40].map((pageSize) => (
+ <option key={pageSize} value={pageSize}>
+ Show {pageSize}
+ </option>
+ ))}
+ </select>
+ </div>
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+ </div>
+ );
};
-
const Wallet = () => {
- const dispatch = useAppDispatch()
- const bpuid = useAppSelector(state => state.app.bpuid)
- const pagination = useAppSelector(state => state.app.txPagination);
-
- useEffect(() => {
- if (!bpuid) return;
-
- new WalletApi().getUserTransactionHistoryProductIdTransactionHistoryGet(
- bpid, // productId
- bpuid, // bpuid
- undefined, // createdAfter
- undefined, // createdBefore
- "-created", // orderBy
- pagination.pageIndex + 1, // page
- pagination.pageSize // pageSize
- ).then(res => {
- const response = res.data as UserLedgerTransactionsResponse;
- dispatch(setUserLedgerSummary(response.summary));
- dispatch(setUserLedgerTxs(response.transactions ?? []))
-
- dispatch(setTxPagination({
- pageIndex: (response.page ?? 1) - 1,
- pageSize: response.size ?? 10,
- }))
- dispatch(setTxTotalItems(response.total ?? 0))
- dispatch(setTxTotalPages(response.pages ?? 9))
- });
-
- }, [bpuid])
-
- if (!bpuid) return null;
-
- return (
- <div className="fixed top-2 left-2 p-2 rounded
+ const dispatch = useAppDispatch();
+ const pagination = useAppSelector((state) => state.app.txPagination);
+ const { data: user } = useGetMeQuery();
+
+ useEffect(() => {
+ if (!user?.product_user_id) return;
+
+ new WalletApi()
+ .getUserTransactionHistoryProductIdTransactionHistoryGet(
+ bpid, // productId
+ user.product_user_id,
+ undefined, // createdAfter
+ undefined, // createdBefore
+ "-created", // orderBy
+ pagination.pageIndex + 1, // page
+ pagination.pageSize, // pageSize
+ )
+ .then((res) => {
+ const response = res.data as UserLedgerTransactionsResponse;
+ dispatch(setUserLedgerSummary(response.summary));
+ dispatch(setUserLedgerTxs(response.transactions ?? []));
+
+ dispatch(
+ setTxPagination({
+ pageIndex: (response.page ?? 1) - 1,
+ pageSize: response.size ?? 10,
+ }),
+ );
+ dispatch(setTxTotalItems(response.total ?? 0));
+ dispatch(setTxTotalPages(response.pages ?? 9));
+ });
+ }, [user?.product_user_id]);
+
+ if (!user?.product_user_id) return null;
+
+ return (
+ <div
+ className="fixed top-2 left-2 p-2 rounded
bg-blue-500 text-white shadow-lg z-50
font-mono
max-h-[calc(100vh-2.5rem)] overflow-y-auto
max-w-[96vw]
- ">
- <WalletHeader />
- <WalletSummary />
- <WalletTransactionsHeader />
- </div>
- )
+ "
+ >
+ <WalletHeader />
+ <WalletSummary />
+ <WalletTransactionsHeader />
+ </div>
+ );
};
-
-export default Wallet; \ No newline at end of file
+export default Wallet;
diff --git a/jb-ui/src/components/ui/button.tsx b/jb-ui/src/components/ui/button.tsx
index b5ea4ab..d2176b4 100644
--- a/jb-ui/src/components/ui/button.tsx
+++ b/jb-ui/src/components/ui/button.tsx
@@ -1,8 +1,8 @@
-import * as React from "react"
-import { cva, type VariantProps } from "class-variance-authority"
-import { Slot } from "radix-ui"
+import * as React from "react";
+import { cva, type VariantProps } from "class-variance-authority";
+import { Slot } from "radix-ui";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
@@ -35,8 +35,8 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
- }
-)
+ },
+);
function Button({
className,
@@ -46,9 +46,9 @@ function Button({
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
- asChild?: boolean
+ asChild?: boolean;
}) {
- const Comp = asChild ? Slot.Root : "button"
+ const Comp = asChild ? Slot.Root : "button";
return (
<Comp
@@ -58,7 +58,7 @@ function Button({
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
- )
+ );
}
-export { Button, buttonVariants }
+export { Button, buttonVariants };
diff --git a/jb-ui/src/components/ui/checkbox.tsx b/jb-ui/src/components/ui/checkbox.tsx
index 0e2a6cd..f24ad45 100644
--- a/jb-ui/src/components/ui/checkbox.tsx
+++ b/jb-ui/src/components/ui/checkbox.tsx
@@ -1,8 +1,8 @@
-import * as React from "react"
-import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
-import { CheckIcon } from "lucide-react"
+import * as React from "react";
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
+import { CheckIcon } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Checkbox({
className,
@@ -13,7 +13,7 @@ function Checkbox({
data-slot="checkbox"
className={cn(
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
- className
+ className,
)}
{...props}
>
@@ -24,7 +24,7 @@ function Checkbox({
<CheckIcon className="size-3.5" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
- )
+ );
}
-export { Checkbox }
+export { Checkbox };
diff --git a/jb-ui/src/components/ui/confetti.tsx b/jb-ui/src/components/ui/confetti.tsx
index e0d353a..57d3273 100644
--- a/jb-ui/src/components/ui/confetti.tsx
+++ b/jb-ui/src/components/ui/confetti.tsx
@@ -1,4 +1,4 @@
-import type { ReactNode } from "react"
+import type { ReactNode } from "react";
import React, {
createContext,
forwardRef,
@@ -7,30 +7,30 @@ import React, {
useImperativeHandle,
useMemo,
useRef,
-} from "react"
+} from "react";
import type {
GlobalOptions as ConfettiGlobalOptions,
CreateTypes as ConfettiInstance,
Options as ConfettiOptions,
-} from "canvas-confetti"
-import confetti from "canvas-confetti"
+} from "canvas-confetti";
+import confetti from "canvas-confetti";
-import { Button } from "@/components/ui/button"
+import { Button } from "@/components/ui/button";
type Api = {
- fire: (options?: ConfettiOptions) => void
-}
+ fire: (options?: ConfettiOptions) => void;
+};
type Props = React.ComponentPropsWithRef<"canvas"> & {
- options?: ConfettiOptions
- globalOptions?: ConfettiGlobalOptions
- manualstart?: boolean
- children?: ReactNode
-}
+ options?: ConfettiOptions;
+ globalOptions?: ConfettiGlobalOptions;
+ manualstart?: boolean;
+ children?: ReactNode;
+};
-export type ConfettiRef = Api | null
+export type ConfettiRef = Api | null;
-const ConfettiContext = createContext<Api>({} as Api)
+const ConfettiContext = createContext<Api>({} as Api);
// Define component first
const ConfettiComponent = forwardRef<ConfettiRef, Props>((props, ref) => {
@@ -40,76 +40,76 @@ const ConfettiComponent = forwardRef<ConfettiRef, Props>((props, ref) => {
manualstart = false,
children,
...rest
- } = props
- const instanceRef = useRef<ConfettiInstance | null>(null)
+ } = props;
+ const instanceRef = useRef<ConfettiInstance | null>(null);
const canvasRef = useCallback(
(node: HTMLCanvasElement) => {
if (node !== null) {
- if (instanceRef.current) return
+ if (instanceRef.current) return;
instanceRef.current = confetti.create(node, {
...globalOptions,
resize: true,
- })
+ });
} else {
if (instanceRef.current) {
- instanceRef.current.reset()
- instanceRef.current = null
+ instanceRef.current.reset();
+ instanceRef.current = null;
}
}
},
- [globalOptions]
- )
+ [globalOptions],
+ );
const fire = useCallback(
async (opts = {}) => {
try {
- await instanceRef.current?.({ ...options, ...opts })
+ await instanceRef.current?.({ ...options, ...opts });
} catch (error) {
- console.error("Confetti error:", error)
+ console.error("Confetti error:", error);
}
},
- [options]
- )
+ [options],
+ );
const api = useMemo(
() => ({
fire,
}),
- [fire]
- )
+ [fire],
+ );
- useImperativeHandle(ref, () => api, [api])
+ useImperativeHandle(ref, () => api, [api]);
useEffect(() => {
if (!manualstart) {
- ;(async () => {
+ (async () => {
try {
- await fire()
+ await fire();
} catch (error) {
- console.error("Confetti effect error:", error)
+ console.error("Confetti effect error:", error);
}
- })()
+ })();
}
- }, [manualstart, fire])
+ }, [manualstart, fire]);
return (
<ConfettiContext.Provider value={api}>
<canvas ref={canvasRef} {...rest} />
{children}
</ConfettiContext.Provider>
- )
-})
+ );
+});
// Set display name immediately
-ConfettiComponent.displayName = "Confetti"
+ConfettiComponent.displayName = "Confetti";
// Export as Confetti
-export const Confetti = ConfettiComponent
+export const Confetti = ConfettiComponent;
interface ConfettiButtonProps extends React.ComponentProps<"button"> {
options?: ConfettiOptions &
- ConfettiGlobalOptions & { canvas?: HTMLCanvasElement }
+ ConfettiGlobalOptions & { canvas?: HTMLCanvasElement };
}
const ConfettiButtonComponent = ({
@@ -119,28 +119,28 @@ const ConfettiButtonComponent = ({
}: ConfettiButtonProps) => {
const handleClick = async (event: React.MouseEvent<HTMLButtonElement>) => {
try {
- const rect = event.currentTarget.getBoundingClientRect()
- const x = rect.left + rect.width / 2
- const y = rect.top + rect.height / 2
+ const rect = event.currentTarget.getBoundingClientRect();
+ const x = rect.left + rect.width / 2;
+ const y = rect.top + rect.height / 2;
await confetti({
...options,
origin: {
x: x / window.innerWidth,
y: y / window.innerHeight,
},
- })
+ });
} catch (error) {
- console.error("Confetti button error:", error)
+ console.error("Confetti button error:", error);
}
- }
+ };
return (
<Button onClick={handleClick} {...props}>
{children}
</Button>
- )
-}
+ );
+};
-ConfettiButtonComponent.displayName = "ConfettiButton"
+ConfettiButtonComponent.displayName = "ConfettiButton";
-export const ConfettiButton = ConfettiButtonComponent
+export const ConfettiButton = ConfettiButtonComponent;
diff --git a/jb-ui/src/components/ui/dot-pattern.tsx b/jb-ui/src/components/ui/dot-pattern.tsx
index 9522b7f..a217a9b 100644
--- a/jb-ui/src/components/ui/dot-pattern.tsx
+++ b/jb-ui/src/components/ui/dot-pattern.tsx
@@ -1,7 +1,7 @@
-import React, { useEffect, useId, useRef, useState } from "react"
-import { motion } from "motion/react"
+import React, { useEffect, useId, useRef, useState } from "react";
+import { motion } from "motion/react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
/**
* DotPattern Component Props
@@ -17,16 +17,16 @@ import { cn } from "@/lib/utils"
* @param {boolean} [glow=false] - Whether dots should have a glowing animation effect
*/
interface DotPatternProps extends React.SVGProps<SVGSVGElement> {
- width?: number
- height?: number
- x?: number
- y?: number
- cx?: number
- cy?: number
- cr?: number
- className?: string
- glow?: boolean
- [key: string]: unknown
+ width?: number;
+ height?: number;
+ x?: number;
+ y?: number;
+ cx?: number;
+ cy?: number;
+ cr?: number;
+ className?: string;
+ glow?: boolean;
+ [key: string]: unknown;
}
/**
@@ -71,22 +71,22 @@ export function DotPattern({
glow = false,
...props
}: DotPatternProps) {
- const id = useId()
- const containerRef = useRef<SVGSVGElement>(null)
- const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
+ const id = useId();
+ const containerRef = useRef<SVGSVGElement>(null);
+ const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const updateDimensions = () => {
if (containerRef.current) {
- const { width, height } = containerRef.current.getBoundingClientRect()
- setDimensions({ width, height })
+ const { width, height } = containerRef.current.getBoundingClientRect();
+ setDimensions({ width, height });
}
- }
+ };
- updateDimensions()
- window.addEventListener("resize", updateDimensions)
- return () => window.removeEventListener("resize", updateDimensions)
- }, [])
+ updateDimensions();
+ window.addEventListener("resize", updateDimensions);
+ return () => window.removeEventListener("resize", updateDimensions);
+ }, []);
const dots = Array.from(
{
@@ -95,16 +95,16 @@ export function DotPattern({
Math.ceil(dimensions.height / height),
},
(_, i) => {
- const col = i % Math.ceil(dimensions.width / width)
- const row = Math.floor(i / Math.ceil(dimensions.width / width))
+ const col = i % Math.ceil(dimensions.width / width);
+ const row = Math.floor(i / Math.ceil(dimensions.width / width));
return {
x: col * width + cx,
y: row * height + cy,
delay: Math.random() * 5,
duration: Math.random() * 3 + 2,
- }
- }
- )
+ };
+ },
+ );
return (
<svg
@@ -112,7 +112,7 @@ export function DotPattern({
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-0 h-full w-full text-neutral-400/80",
- className
+ className,
)}
{...props}
>
@@ -152,5 +152,5 @@ export function DotPattern({
/>
))}
</svg>
- )
+ );
}
diff --git a/jb-ui/src/components/ui/field.tsx b/jb-ui/src/components/ui/field.tsx
index db0dc12..77546e5 100644
--- a/jb-ui/src/components/ui/field.tsx
+++ b/jb-ui/src/components/ui/field.tsx
@@ -1,9 +1,9 @@
-import { useMemo } from "react"
-import { cva, type VariantProps } from "class-variance-authority"
+import { useMemo } from "react";
+import { cva, type VariantProps } from "class-variance-authority";
-import { cn } from "@/lib/utils"
-import { Label } from "@/components/ui/label"
-import { Separator } from "@/components/ui/separator"
+import { cn } from "@/lib/utils";
+import { Label } from "@/components/ui/label";
+import { Separator } from "@/components/ui/separator";
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
return (
@@ -12,11 +12,11 @@ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
className={cn(
"flex flex-col gap-6",
"has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function FieldLegend({
@@ -32,11 +32,11 @@ function FieldLegend({
"mb-3 font-medium",
"data-[variant=legend]:text-base",
"data-[variant=label]:text-sm",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
@@ -45,11 +45,11 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
data-slot="field-group"
className={cn(
"group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
const fieldVariants = cva(
@@ -73,8 +73,8 @@ const fieldVariants = cva(
defaultVariants: {
orientation: "vertical",
},
- }
-)
+ },
+);
function Field({
className,
@@ -89,7 +89,7 @@ function Field({
className={cn(fieldVariants({ orientation }), className)}
{...props}
/>
- )
+ );
}
function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
@@ -98,11 +98,11 @@ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
data-slot="field-content"
className={cn(
"group/field-content flex flex-1 flex-col gap-1.5 leading-snug",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function FieldLabel({
@@ -116,11 +116,11 @@ function FieldLabel({
"group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50",
"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4",
"has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
@@ -129,11 +129,11 @@ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
data-slot="field-label"
className={cn(
"flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
@@ -144,11 +144,11 @@ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
"text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance",
"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function FieldSeparator({
@@ -156,7 +156,7 @@ function FieldSeparator({
className,
...props
}: React.ComponentProps<"div"> & {
- children?: React.ReactNode
+ children?: React.ReactNode;
}) {
return (
<div
@@ -164,7 +164,7 @@ function FieldSeparator({
data-content={!!children}
className={cn(
"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2",
- className
+ className,
)}
{...props}
>
@@ -178,7 +178,7 @@ function FieldSeparator({
</span>
)}
</div>
- )
+ );
}
function FieldError({
@@ -187,37 +187,37 @@ function FieldError({
errors,
...props
}: React.ComponentProps<"div"> & {
- errors?: Array<{ message?: string } | undefined>
+ errors?: Array<{ message?: string } | undefined>;
}) {
const content = useMemo(() => {
if (children) {
- return children
+ return children;
}
if (!errors?.length) {
- return null
+ return null;
}
const uniqueErrors = [
...new Map(errors.map((error) => [error?.message, error])).values(),
- ]
+ ];
if (uniqueErrors?.length == 1) {
- return uniqueErrors[0]?.message
+ return uniqueErrors[0]?.message;
}
return (
<ul className="ml-4 flex list-disc flex-col gap-1">
{uniqueErrors.map(
(error, index) =>
- error?.message && <li key={index}>{error.message}</li>
+ error?.message && <li key={index}>{error.message}</li>,
)}
</ul>
- )
- }, [children, errors])
+ );
+ }, [children, errors]);
if (!content) {
- return null
+ return null;
}
return (
@@ -229,7 +229,7 @@ function FieldError({
>
{content}
</div>
- )
+ );
}
export {
@@ -243,4 +243,4 @@ export {
FieldSet,
FieldContent,
FieldTitle,
-}
+};
diff --git a/jb-ui/src/components/ui/label.tsx b/jb-ui/src/components/ui/label.tsx
index ef7133a..4ef28a9 100644
--- a/jb-ui/src/components/ui/label.tsx
+++ b/jb-ui/src/components/ui/label.tsx
@@ -1,7 +1,7 @@
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
+import * as React from "react";
+import * as LabelPrimitive from "@radix-ui/react-label";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Label({
className,
@@ -12,11 +12,11 @@ function Label({
data-slot="label"
className={cn(
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
-export { Label }
+export { Label };
diff --git a/jb-ui/src/components/ui/magic-card.tsx b/jb-ui/src/components/ui/magic-card.tsx
index e6503d8..2b92e38 100644
--- a/jb-ui/src/components/ui/magic-card.tsx
+++ b/jb-ui/src/components/ui/magic-card.tsx
@@ -1,16 +1,16 @@
-import React, { useCallback, useEffect } from "react"
-import { motion, useMotionTemplate, useMotionValue } from "motion/react"
+import React, { useCallback, useEffect } from "react";
+import { motion, useMotionTemplate, useMotionValue } from "motion/react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
interface MagicCardProps {
- children?: React.ReactNode
- className?: string
- gradientSize?: number
- gradientColor?: string
- gradientOpacity?: number
- gradientFrom?: string
- gradientTo?: string
+ children?: React.ReactNode;
+ className?: string;
+ gradientSize?: number;
+ gradientColor?: string;
+ gradientOpacity?: number;
+ gradientFrom?: string;
+ gradientTo?: string;
}
export function MagicCard({
@@ -22,49 +22,49 @@ export function MagicCard({
gradientFrom = "#9E7AFF",
gradientTo = "#FE8BBB",
}: MagicCardProps) {
- const mouseX = useMotionValue(-gradientSize)
- const mouseY = useMotionValue(-gradientSize)
+ const mouseX = useMotionValue(-gradientSize);
+ const mouseY = useMotionValue(-gradientSize);
const reset = useCallback(() => {
- mouseX.set(-gradientSize)
- mouseY.set(-gradientSize)
- }, [gradientSize, mouseX, mouseY])
+ mouseX.set(-gradientSize);
+ mouseY.set(-gradientSize);
+ }, [gradientSize, mouseX, mouseY]);
const handlePointerMove = useCallback(
(e: React.PointerEvent<HTMLDivElement>) => {
- const rect = e.currentTarget.getBoundingClientRect()
- mouseX.set(e.clientX - rect.left)
- mouseY.set(e.clientY - rect.top)
+ const rect = e.currentTarget.getBoundingClientRect();
+ mouseX.set(e.clientX - rect.left);
+ mouseY.set(e.clientY - rect.top);
},
- [mouseX, mouseY]
- )
+ [mouseX, mouseY],
+ );
useEffect(() => {
- reset()
- }, [reset])
+ reset();
+ }, [reset]);
useEffect(() => {
const handleGlobalPointerOut = (e: PointerEvent) => {
if (!e.relatedTarget) {
- reset()
+ reset();
}
- }
+ };
const handleVisibility = () => {
if (document.visibilityState !== "visible") {
- reset()
+ reset();
}
- }
+ };
- window.addEventListener("pointerout", handleGlobalPointerOut)
- window.addEventListener("blur", reset)
- document.addEventListener("visibilitychange", handleVisibility)
+ window.addEventListener("pointerout", handleGlobalPointerOut);
+ window.addEventListener("blur", reset);
+ document.addEventListener("visibilitychange", handleVisibility);
return () => {
- window.removeEventListener("pointerout", handleGlobalPointerOut)
- window.removeEventListener("blur", reset)
- document.removeEventListener("visibilitychange", handleVisibility)
- }
- }, [reset])
+ window.removeEventListener("pointerout", handleGlobalPointerOut);
+ window.removeEventListener("blur", reset);
+ document.removeEventListener("visibilitychange", handleVisibility);
+ };
+ }, [reset]);
return (
<div
@@ -97,5 +97,5 @@ export function MagicCard({
/>
<div className="relative">{children}</div>
</div>
- )
+ );
}
diff --git a/jb-ui/src/components/ui/pagination.tsx b/jb-ui/src/components/ui/pagination.tsx
index 1dcfb0c..990f907 100644
--- a/jb-ui/src/components/ui/pagination.tsx
+++ b/jb-ui/src/components/ui/pagination.tsx
@@ -1,12 +1,12 @@
-import * as React from "react"
+import * as React from "react";
import {
ChevronLeftIcon,
ChevronRightIcon,
MoreHorizontalIcon,
-} from "lucide-react"
+} from "lucide-react";
-import { cn } from "@/lib/utils"
-import { buttonVariants, type Button } from "@/components/ui/button"
+import { cn } from "@/lib/utils";
+import { buttonVariants, type Button } from "@/components/ui/button";
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
return (
@@ -17,7 +17,7 @@ function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
className={cn("mx-auto flex w-full justify-center", className)}
{...props}
/>
- )
+ );
}
function PaginationContent({
@@ -30,17 +30,17 @@ function PaginationContent({
className={cn("flex flex-row items-center gap-1", className)}
{...props}
/>
- )
+ );
}
function PaginationItem({ ...props }: React.ComponentProps<"li">) {
- return <li data-slot="pagination-item" {...props} />
+ return <li data-slot="pagination-item" {...props} />;
}
type PaginationLinkProps = {
- isActive?: boolean
+ isActive?: boolean;
} & Pick<React.ComponentProps<typeof Button>, "size"> &
- React.ComponentProps<"a">
+ React.ComponentProps<"a">;
function PaginationLink({
className,
@@ -58,11 +58,11 @@ function PaginationLink({
variant: isActive ? "outline" : "ghost",
size,
}),
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function PaginationPrevious({
@@ -79,7 +79,7 @@ function PaginationPrevious({
<ChevronLeftIcon />
<span className="hidden sm:block">Previous</span>
</PaginationLink>
- )
+ );
}
function PaginationNext({
@@ -96,7 +96,7 @@ function PaginationNext({
<span className="hidden sm:block">Next</span>
<ChevronRightIcon />
</PaginationLink>
- )
+ );
}
function PaginationEllipsis({
@@ -113,7 +113,7 @@ function PaginationEllipsis({
<MoreHorizontalIcon className="size-4" />
<span className="sr-only">More pages</span>
</span>
- )
+ );
}
export {
@@ -124,4 +124,4 @@ export {
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
-}
+};
diff --git a/jb-ui/src/components/ui/separator.tsx b/jb-ui/src/components/ui/separator.tsx
index 275381c..72c18e3 100644
--- a/jb-ui/src/components/ui/separator.tsx
+++ b/jb-ui/src/components/ui/separator.tsx
@@ -1,9 +1,9 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
+import * as React from "react";
+import * as SeparatorPrimitive from "@radix-ui/react-separator";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Separator({
className,
@@ -18,11 +18,11 @@ function Separator({
orientation={orientation}
className={cn(
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
-export { Separator }
+export { Separator };
diff --git a/jb-ui/src/components/ui/skeleton.tsx b/jb-ui/src/components/ui/skeleton.tsx
index 32ea0ef..0168998 100644
--- a/jb-ui/src/components/ui/skeleton.tsx
+++ b/jb-ui/src/components/ui/skeleton.tsx
@@ -1,4 +1,4 @@
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
return (
@@ -7,7 +7,7 @@ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
className={cn("bg-accent animate-pulse rounded-md", className)}
{...props}
/>
- )
+ );
}
-export { Skeleton }
+export { Skeleton };
diff --git a/jb-ui/src/hooks.ts b/jb-ui/src/hooks.ts
index 02ff1b6..7f8db4b 100644
--- a/jb-ui/src/hooks.ts
+++ b/jb-ui/src/hooks.ts
@@ -1,11 +1,11 @@
// This file serves as a central hub for re-exporting pre-typed Redux hooks.
-import { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'
-import type { AppDispatch, RootState } from '@/store'
-
+import { useDispatch, useSelector, TypedUseSelectorHook } from "react-redux";
+import type { AppDispatch, RootState } from "@/store";
// Use throughout your app instead of plain `useDispatch` and `useSelector`
// export const useAppDispatch: () => AppDispatch = useDispatch.withTypes<AppDispatch>()
-export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector.withTypes<RootState>()
+export const useAppSelector: TypedUseSelectorHook<RootState> =
+ useSelector.withTypes<RootState>();
-export const useAppDispatch: () => AppDispatch = useDispatch
+export const useAppDispatch: () => AppDispatch = useDispatch;
// export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
diff --git a/jb-ui/src/index.css b/jb-ui/src/index.css
index 1677b7b..579102b 100644
--- a/jb-ui/src/index.css
+++ b/jb-ui/src/index.css
@@ -138,4 +138,3 @@
@apply bg-background text-foreground;
}
}
-
diff --git a/jb-ui/src/lib/utils.ts b/jb-ui/src/lib/utils.ts
index 0c84192..1aa59c6 100644
--- a/jb-ui/src/lib/utils.ts
+++ b/jb-ui/src/lib/utils.ts
@@ -1,113 +1,119 @@
-import { type ClassValue, clsx } from "clsx"
-import { twMerge } from "tailwind-merge"
-import { Source } from "../api_fsb"
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+import { Source } from "../api_fsb";
export const routeBasename = import.meta.env.VITE_BASENAME;
-export const tagManager = import.meta.env.VITE_TAG_MANAGER
+export const tagManager = import.meta.env.VITE_TAG_MANAGER;
export const bpid = import.meta.env.VITE_BPID;
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs));
}
export function assert(condition: any, msg?: string): asserts condition {
- if (!condition) {
- throw new Error(msg);
- }
+ if (!condition) {
+ throw new Error(msg);
+ }
}
export function toCapitalized(word: string): string {
- return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}
-export function truncate(originalText: string, maxLength: number = 10, replaceStr = "…"): string {
- if (originalText && originalText.length > maxLength) {
- return originalText.substring(0, maxLength) + replaceStr;
- }
- return originalText;
+export function truncate(
+ originalText: string,
+ maxLength: number = 10,
+ replaceStr = "…",
+): string {
+ if (originalText && originalText.length > maxLength) {
+ return originalText.substring(0, maxLength) + replaceStr;
+ }
+ return originalText;
}
export function usdCentFmt(value: number): string {
- return (value / 100).toLocaleString('en-US', {
- style: 'currency',
- currency: 'USD',
- minimumFractionDigits: 2,
- maximumFractionDigits: 2
- })
+ return (value / 100).toLocaleString("en-US", {
+ style: "currency",
+ currency: "USD",
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ });
}
export function formatStatus(status: string): string {
- const table = {
- 'c': 'Completed',
- 't': 'Terminated',
- 'f': 'Failed',
- 'e': 'Entered',
- }
-
- return table[status as keyof typeof table] ?? "Unknown";
+ const table = {
+ c: "Completed",
+ t: "Terminated",
+ f: "Failed",
+ e: "Entered",
+ };
+
+ return table[status as keyof typeof table] ?? "Unknown";
}
export function formatSource(source: Source): string {
- const table = {
- 'g': 'GRS',
- 'c': 'Cint',
- 'a': 'Dalia',
- 'd': 'Dynata',
- 'et': 'Etx',
- 'f': 'Full Circle',
- 'i': 'InnovateMR',
- 'l': 'Lucid',
- 'm': 'Morning Consult',
- 'n': 'Open Labs',
- 'o': 'Pollfish',
- 'e': 'Precision Sample',
- 'r': 'Prodege User',
- 'pr': 'Prodege',
- 'p': 'Pulley',
- 'rd': 'Rep Data',
- 'h': 'Sago',
- 's': 'Pure Spectrum',
- 't': 'Testing',
- 'u': 'Testing 2',
- 'w': 'WXET'
- }
-
- return table[source]
+ const table = {
+ g: "GRS",
+ c: "Cint",
+ a: "Dalia",
+ d: "Dynata",
+ et: "Etx",
+ f: "Full Circle",
+ i: "InnovateMR",
+ l: "Lucid",
+ m: "Morning Consult",
+ n: "Open Labs",
+ o: "Pollfish",
+ e: "Precision Sample",
+ r: "Prodege User",
+ pr: "Prodege",
+ p: "Pulley",
+ rd: "Rep Data",
+ h: "Sago",
+ s: "Pure Spectrum",
+ t: "Testing",
+ u: "Testing 2",
+ w: "WXET",
+ };
+
+ return table[source];
}
export function formatSecondsVerbose(seconds: number): string {
- const mins = Math.floor(seconds / 60)
- const secs = seconds % 60
-
- const parts = []
- if (mins > 0) parts.push(`${mins} min`)
- if (secs > 0 || mins === 0) {
- parts.push(`${secs.toLocaleString('en-US', {
- minimumFractionDigits: 0,
- maximumFractionDigits: 1
- })} sec`)
- }
-
- return parts.join(" ")
+ const mins = Math.floor(seconds / 60);
+ const secs = seconds % 60;
+
+ const parts = [];
+ if (mins > 0) parts.push(`${mins} min`);
+ if (secs > 0 || mins === 0) {
+ parts.push(
+ `${secs.toLocaleString("en-US", {
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 1,
+ })} sec`,
+ );
+ }
+
+ return parts.join(" ");
}
export function formatSeconds(seconds: number): string {
- const mins = Math.floor(seconds / 60)
- const secs = seconds % 60
- const paddedSecs = secs.toString().padStart(2, '0')
- return `${mins}:${paddedSecs}`
+ const mins = Math.floor(seconds / 60);
+ const secs = seconds % 60;
+ const paddedSecs = secs.toString().padStart(2, "0");
+ return `${mins}:${paddedSecs}`;
}
export function formatCentsToUSD(cents: number): string {
- return new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency: 'USD',
- }).format(cents / 100)
+ return new Intl.NumberFormat("en-US", {
+ style: "currency",
+ currency: "USD",
+ }).format(cents / 100);
}
export function titleCase(str: string): string {
- return str
- .split(" ")
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
- .join(" ");
-} \ No newline at end of file
+ return str
+ .split(" ")
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(" ");
+}
diff --git a/jb-ui/src/main.tsx b/jb-ui/src/main.tsx
index 538bea2..6e02727 100644
--- a/jb-ui/src/main.tsx
+++ b/jb-ui/src/main.tsx
@@ -1,19 +1,19 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import { Provider } from 'react-redux'
-import { store } from '@/store'
+import React from "react";
+import ReactDOM from "react-dom/client";
+import { Provider } from "react-redux";
+import { store } from "@/store";
import JBApp from "@/JBApp";
-const rootElement = document.getElementById('root');
+const rootElement = document.getElementById("root");
if (!rootElement) {
- throw new Error('Failed to find the root element');
+ throw new Error("Failed to find the root element");
}
const root = ReactDOM.createRoot(rootElement);
root.render(
- <React.StrictMode>
- <Provider store={store}>
- <JBApp />
- </Provider>
- </React.StrictMode >
-); \ No newline at end of file
+ <React.StrictMode>
+ <Provider store={store}>
+ <JBApp />
+ </Provider>
+ </React.StrictMode>,
+);
diff --git a/jb-ui/src/models/app.ts b/jb-ui/src/models/app.ts
index 95b4c11..db54e0d 100644
--- a/jb-ui/src/models/app.ts
+++ b/jb-ui/src/models/app.ts
@@ -1,37 +1,47 @@
import {
- UserWalletBalance, TopNPlusBucket, TaskStatusResponse,
- UserLedgerTransactionTypesSummary,
- UserLedgerTransactionsResponseTransactionsInner,
- OfferwallReason
+ UserWalletBalance,
+ TopNPlusBucket,
+ TaskStatusResponse,
+ UserLedgerTransactionTypesSummary,
+ UserLedgerTransactionsResponseTransactionsInner,
+ OfferwallReason,
+ UserLedgerWallet,
+ UserDisplayedWalletBalance,
} from "@/api_fsb";
-import { PaginationState } from '@tanstack/react-table';
+import { PaginationState } from "@tanstack/react-table";
export interface App {
- // Global IDs needed by GRL + MTurk
- bpuid?: string;
- assignment_id?: string;
- turkSubmitTo?: string;
+ // Global IDs needed by GRL + MTurk
+ bpuid?: string;
+ assignment_id?: string;
+ turkSubmitTo?: string;
- // Global UI settings
- loi: number;
- availability_count?: number;
- attempted_live_eligible_count?: number;
- offerwall_reasons: OfferwallReason[];
+ // Global UI settings
+ loi: number;
+ availability_count?: number;
+ attempted_live_eligible_count?: number;
+ offerwall_reasons: OfferwallReason[];
- // The timestamp of when the currently requested bucket was requested. We want
- // to save this to prevent it from sitting for longer than 120 seconds.
- currentBucketRequested?: number; // Date.now() is a timestamp in ms
- currentBuckets?: TopNPlusBucket[];
- currentBucketEntered?: number; // Date.now() is a timestamp in ms
- taskStatus?: TaskStatusResponse;
+ // The timestamp of when the currently requested bucket was requested. We want
+ // to save this to prevent it from sitting for longer than 120 seconds.
+ currentBucketRequested?: number; // Date.now() is a timestamp in ms
+ currentBuckets?: TopNPlusBucket[];
+ currentBucketEntered?: number; // Date.now() is a timestamp in ms
+ taskStatus?: TaskStatusResponse;
- // Wallet stuff
- userWalletBalance?: UserWalletBalance;
- userLedgerSummary?: UserLedgerTransactionTypesSummary;
- userLedgerTxCount?: number;
- userLedgerTxs: UserLedgerTransactionsResponseTransactionsInner[];
+ // Wallet stuff
+ userWalletBalance?: UserWalletBalance;
+ userLedgerSummary?: UserLedgerTransactionTypesSummary;
+ userLedgerTxCount?: number;
+ userLedgerTxs: UserLedgerTransactionsResponseTransactionsInner[];
- txPagination: PaginationState;
- txTotalItems?: number;
- txTotalPages?: number;
+ // --- new approach
+ userDisplayedWalletBalance?: UserDisplayedWalletBalance;
+ userWallet?: UserLedgerWallet;
+ userAttemptCreditWallet?: UserLedgerWallet;
+ // ---
+
+ txPagination: PaginationState;
+ txTotalItems?: number;
+ txTotalPages?: number;
}
diff --git a/jb-ui/src/models/appSlice.ts b/jb-ui/src/models/appSlice.ts
index 87952d9..42a776e 100644
--- a/jb-ui/src/models/appSlice.ts
+++ b/jb-ui/src/models/appSlice.ts
@@ -1,188 +1,221 @@
import {
- TaskStatusResponse,
- TopNPlusBucket,
- UserLedgerTransactionsResponseTransactionsInner,
- UserLedgerTransactionTypesSummary,
- UserWalletBalance,
- OfferwallReason
+ TaskStatusResponse,
+ TopNPlusBucket,
+ UserLedgerTransactionsResponseTransactionsInner,
+ UserLedgerTransactionTypesSummary,
+ UserWalletBalance,
+ UserDisplayedWalletBalance,
+ UserLedgerWallet,
+ OfferwallReason,
} from "@/api_fsb";
import { App } from "@/models/app";
import { RootState } from "@/store";
-import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { PaginationState } from '@tanstack/react-table';
+import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit";
+import { PaginationState } from "@tanstack/react-table";
import moment from "moment";
const initialState: App = {
- bpuid: undefined,
- assignment_id: undefined,
- loi: 1800,
- currentBuckets: undefined,
- currentBucketEntered: undefined,
- taskStatus: undefined,
- offerwall_reasons: [],
-
- userWalletBalance: undefined,
- userLedgerSummary: undefined,
- userLedgerTxCount: undefined,
- userLedgerTxs: [],
-
- txPagination: { pageIndex: 0, pageSize: 10 },
- txTotalItems: undefined,
- txTotalPages: undefined
-} as App
+ bpuid: undefined,
+ assignment_id: undefined,
+ loi: 1800,
+ currentBuckets: undefined,
+ currentBucketEntered: undefined,
+ taskStatus: undefined,
+ offerwall_reasons: [],
+
+ userWalletBalance: undefined,
+ userLedgerSummary: undefined,
+ userLedgerTxCount: undefined,
+ userLedgerTxs: [],
+
+ // --- new approach
+ userDisplayedWalletBalance: undefined,
+ userWallet: undefined,
+ userAttemptCreditWallet: undefined,
+ // ---
+
+ txPagination: { pageIndex: 0, pageSize: 10 },
+ txTotalItems: undefined,
+ txTotalPages: undefined,
+} as App;
const appSlice = createSlice({
- name: 'app',
- initialState,
- reducers: {
-
- setProductUserID(state, action: PayloadAction<string>) {
- state.bpuid = action.payload;
- },
-
- setAssignmentID(state, action: PayloadAction<string>) {
- // This is really so silly. Amazon should simply not send
- // anything if it's unavailable.
- if (action.payload === "ASSIGNMENT_ID_NOT_AVAILABLE") {
- state.assignment_id = undefined;
- }
- state.assignment_id = action.payload;
- },
-
- setTurkSubmitTo(state, action: PayloadAction<string>) {
- state.turkSubmitTo = action.payload;
- },
-
- setLOI(state, action: PayloadAction<number>) {
- state.loi = action.payload;
- },
-
- setAvailabilityCount(state, action: PayloadAction<number>) {
- state.availability_count = action.payload
- },
-
- setAttemptedLiveEligibleCount(state, action: PayloadAction<number>) {
- state.attempted_live_eligible_count = action.payload
- },
-
- setCurrentBuckets(state, action: PayloadAction<TopNPlusBucket[] | undefined>) {
- state.currentBucketRequested = moment.utc().unix();
- state.currentBuckets = action.payload
- },
-
- setOfferwallReasons(state, action: PayloadAction<OfferwallReason[]>) {
- state.offerwall_reasons = action.payload;
- },
-
- setEnteredTimestamp(state) {
- // Go back by 2 seconds to account for any time drift
- state.currentBucketEntered = moment.utc().unix() - 2;
- },
-
- setTaskStatus(state, action: PayloadAction<TaskStatusResponse>) {
- state.taskStatus = action.payload;
-
- state.bpuid = action.payload.product_user_id;
- },
-
- setUserWalletBalance(state, action: PayloadAction<UserWalletBalance>) {
- state.userWalletBalance = action.payload;
- },
-
- setUserLedgerSummary(state, action: PayloadAction<UserLedgerTransactionTypesSummary>) {
- state.userLedgerSummary = action.payload;
- },
-
- setUserLedgerTxs(state, action: PayloadAction<UserLedgerTransactionsResponseTransactionsInner[]>) {
- // We're not appending the transaction details, it's only going
- // to reassign the current page of Transactions.
- state.userLedgerTxs = action.payload;
- },
-
- setTxPagination(state, action: PayloadAction<PaginationState>) {
- state.txPagination = action.payload;
- },
-
- setTxTotalItems(state, action: PayloadAction<number>) {
- state.txTotalItems = action.payload;
- },
-
- setTxTotalPages(state, action: PayloadAction<number>) {
- state.txTotalPages = action.payload;
- }
-
- }
-})
+ name: "app",
+ initialState,
+ reducers: {
+ setProductUserID(state, action: PayloadAction<string>) {
+ state.bpuid = action.payload;
+ },
+
+ setAssignmentID(state, action: PayloadAction<string>) {
+ // This is really so silly. Amazon should simply not send
+ // anything if it's unavailable.
+ if (action.payload === "ASSIGNMENT_ID_NOT_AVAILABLE") {
+ state.assignment_id = undefined;
+ }
+ state.assignment_id = action.payload;
+ },
+
+ setTurkSubmitTo(state, action: PayloadAction<string>) {
+ state.turkSubmitTo = action.payload;
+ },
+
+ setLOI(state, action: PayloadAction<number>) {
+ state.loi = action.payload;
+ },
+
+ setAvailabilityCount(state, action: PayloadAction<number>) {
+ state.availability_count = action.payload;
+ },
+
+ setAttemptedLiveEligibleCount(state, action: PayloadAction<number>) {
+ state.attempted_live_eligible_count = action.payload;
+ },
+
+ setCurrentBuckets(
+ state,
+ action: PayloadAction<TopNPlusBucket[] | undefined>,
+ ) {
+ state.currentBucketRequested = moment.utc().unix();
+ state.currentBuckets = action.payload;
+ },
+
+ setOfferwallReasons(state, action: PayloadAction<OfferwallReason[]>) {
+ state.offerwall_reasons = action.payload;
+ },
+
+ setEnteredTimestamp(state) {
+ // Go back by 2 seconds to account for any time drift
+ state.currentBucketEntered = moment.utc().unix() - 2;
+ },
+
+ setTaskStatus(state, action: PayloadAction<TaskStatusResponse>) {
+ state.taskStatus = action.payload;
+
+ state.bpuid = action.payload.product_user_id;
+ },
+
+ setUserWalletBalance(state, action: PayloadAction<UserWalletBalance>) {
+ state.userWalletBalance = action.payload;
+ },
+
+ // --- New approach ---
+ setUserDisplayedWalletBalance(
+ state,
+ action: PayloadAction<UserDisplayedWalletBalance>,
+ ) {
+ state.userDisplayedWalletBalance = action.payload;
+ },
+
+ setUserWallet(state, action: PayloadAction<UserLedgerWallet>) {
+ state.userWallet = action.payload;
+ },
+
+ setUserAttemptCreditWallet(state, action: PayloadAction<UserLedgerWallet>) {
+ state.userAttemptCreditWallet = action.payload;
+ },
+
+ // --- ---
+
+ setUserLedgerSummary(
+ state,
+ action: PayloadAction<UserLedgerTransactionTypesSummary>,
+ ) {
+ state.userLedgerSummary = action.payload;
+ },
+
+ setUserLedgerTxs(
+ state,
+ action: PayloadAction<UserLedgerTransactionsResponseTransactionsInner[]>,
+ ) {
+ // We're not appending the transaction details, it's only going
+ // to reassign the current page of Transactions.
+ state.userLedgerTxs = action.payload;
+ },
+
+ setTxPagination(state, action: PayloadAction<PaginationState>) {
+ state.txPagination = action.payload;
+ },
+
+ setTxTotalItems(state, action: PayloadAction<number>) {
+ state.txTotalItems = action.payload;
+ },
+
+ setTxTotalPages(state, action: PayloadAction<number>) {
+ state.txTotalPages = action.payload;
+ },
+ },
+});
export const {
- setProductUserID,
- setAssignmentID,
- setTurkSubmitTo,
- setLOI,
- setAvailabilityCount,
- setAttemptedLiveEligibleCount,
- setOfferwallReasons,
- setCurrentBuckets,
- setEnteredTimestamp,
- setTaskStatus,
-
- setUserWalletBalance,
-
- setUserLedgerSummary,
- setUserLedgerTxs,
-
- setTxPagination,
- setTxTotalItems,
- setTxTotalPages
+ setProductUserID,
+ setAssignmentID,
+ setTurkSubmitTo,
+ setLOI,
+ setAvailabilityCount,
+ setAttemptedLiveEligibleCount,
+ setOfferwallReasons,
+ setCurrentBuckets,
+ setEnteredTimestamp,
+ setTaskStatus,
+
+ setUserWalletBalance,
+
+ setUserLedgerSummary,
+ setUserLedgerTxs,
+
+ setUserDisplayedWalletBalance,
+ setUserWallet,
+ setUserAttemptCreditWallet,
+
+ setTxPagination,
+ setTxTotalItems,
+ setTxTotalPages,
} = appSlice.actions;
-export default appSlice.reducer
+export default appSlice.reducer;
export const getLOIText = createSelector(
- [(state: RootState) => state.app],
- (app_config): string => {
-
- const lookup: Record<number, string> = {
- 600: "ten",
- 1200: "twenty",
- 1800: "thirty",
- };
-
- return lookup[app_config.loi] || " – ";
- }
+ [(state: RootState) => state.app],
+ (app_config): string => {
+ const lookup: Record<number, string> = {
+ 600: "ten",
+ 1200: "twenty",
+ 1800: "thirty",
+ };
+
+ return lookup[app_config.loi] || " – ";
+ },
);
export const getAvailabilityCount = createSelector(
- [(state: RootState) => state.app],
- (app_config): number | undefined => {
- return app_config.availability_count;
- }
+ [(state: RootState) => state.app],
+ (app_config): number | undefined => {
+ return app_config.availability_count;
+ },
);
export const isLowBalance = createSelector(
- [(state: RootState) => state.app],
- (app_config): boolean => {
- const bal_amt = app_config.userWalletBalance?.amount ?? 0
- return bal_amt <= -90;
- }
+ [(state: RootState) => state.app],
+ (app_config): boolean => {
+ const bal_amt = app_config.userWalletBalance?.amount ?? 0;
+ return bal_amt <= -90;
+ },
);
-
export const selectBucket = createSelector(
- [
- (state: RootState) => state.app.currentBuckets,
- ],
- (buckets): TopNPlusBucket | null => {
- if (buckets && buckets.length >= 1) {
- return buckets[0]
- }
- return null;
+ [(state: RootState) => state.app.currentBuckets],
+ (buckets): TopNPlusBucket | null => {
+ if (buckets && buckets.length >= 1) {
+ return buckets[0];
}
+ return null;
+ },
);
export const getSurveyURL = createSelector(
- [selectBucket],
- (bucket): string | null => {
- return bucket?.uri || null;
- }
-); \ No newline at end of file
+ [selectBucket],
+ (bucket): string | null => {
+ return bucket?.uri || null;
+ },
+);
diff --git a/jb-ui/src/models/authAPI.ts b/jb-ui/src/models/authAPI.ts
new file mode 100644
index 0000000..fa08bc7
--- /dev/null
+++ b/jb-ui/src/models/authAPI.ts
@@ -0,0 +1,24 @@
+import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
+import type { User } from "@/types/authApi";
+
+export const authApi = createApi({
+ reducerPath: "authApi",
+ baseQuery: fetchBaseQuery({
+ baseUrl: "/auth",
+ credentials: "include", // sends the httpOnly cookie
+ }),
+ tagTypes: ["User"],
+ endpoints: (builder) => ({
+ getMe: builder.query<User, void>({
+ query: () => "/session",
+ providesTags: ["User"],
+ }),
+ // logout: builder.mutation({
+ // query: () => ({ url: "/de-session", method: "POST" }),
+ // invalidatesTags: ["User"],
+ // }),
+ }),
+});
+
+// export const { useGetMeQuery, useLogoutMutation } = authApi;
+export const { useGetMeQuery } = authApi;
diff --git a/jb-ui/src/models/cashoutMethodsSlice.ts b/jb-ui/src/models/cashoutMethodsSlice.ts
new file mode 100644
index 0000000..92c03da
--- /dev/null
+++ b/jb-ui/src/models/cashoutMethodsSlice.ts
@@ -0,0 +1,37 @@
+import { CashoutMethodOut } from "@/api_fsb";
+import type { RootState } from "@/store";
+import { createSlice, createEntityAdapter } from "@reduxjs/toolkit";
+
+// Entity adapter for normalized storage
+const cashoutMethodsAdapter = createEntityAdapter({
+ selectId: (model: CashoutMethodOut) => model.id!,
+ sortComparer: (a, b) => {
+ return (b.min_value ?? 0) - (a.min_value ?? 0);
+ },
+});
+
+const cashoutMethodsSlice = createSlice({
+ name: "cashoutMethods",
+ initialState: cashoutMethodsAdapter.getInitialState(),
+
+ reducers: {
+ addCashoutMethod: cashoutMethodsAdapter.addOne,
+ addCashoutMethods: cashoutMethodsAdapter.addMany,
+ upsertCashoutMethod: cashoutMethodsAdapter.upsertOne, // Add or Update
+ },
+});
+
+export const { addCashoutMethod, addCashoutMethods, upsertCashoutMethod } =
+ cashoutMethodsSlice.actions;
+
+export const cashoutMethodsSelectors = cashoutMethodsAdapter.getSelectors(
+ (state: RootState) => state.cashoutMethods,
+);
+
+export const selectAllCashoutMethods = (
+ state: RootState,
+): CashoutMethodOut[] => {
+ return cashoutMethodsSelectors.selectAll(state) ?? [];
+};
+
+export default cashoutMethodsSlice.reducer;
diff --git a/jb-ui/src/models/grlEventsSlice.ts b/jb-ui/src/models/grlEventsSlice.ts
index 912c4ca..681c22e 100644
--- a/jb-ui/src/models/grlEventsSlice.ts
+++ b/jb-ui/src/models/grlEventsSlice.ts
@@ -1,58 +1,56 @@
import { EventEnvelope } from "@/api_fsb";
import { RootState } from "@/store";
-import { createEntityAdapter, createSelector, createSlice } from '@reduxjs/toolkit';
+import {
+ createEntityAdapter,
+ createSelector,
+ createSlice,
+} from "@reduxjs/toolkit";
const eventAdapter = createEntityAdapter({
- selectId: (model: EventEnvelope) => model.event_uuid!,
- sortComparer: (a, b) => {
- // ASC by timestamp
- return a.timestamp!.localeCompare(b.timestamp!);
- },
+ selectId: (model: EventEnvelope) => model.event_uuid!,
+ sortComparer: (a, b) => {
+ // ASC by timestamp
+ return a.timestamp!.localeCompare(b.timestamp!);
+ },
});
-
const grlEventsSlice = createSlice({
- name: 'grlEvents',
- initialState: eventAdapter.getInitialState(),
-
- reducers: {
- addEvent: eventAdapter.addOne,
- addEvents: eventAdapter.addMany,
- upsertEvent: eventAdapter.upsertOne, // Add or Update
-
- }
-})
-
-
-export const {
- addEvent, addEvents, upsertEvent
-} = grlEventsSlice.actions;
+ name: "grlEvents",
+ initialState: eventAdapter.getInitialState(),
+
+ reducers: {
+ addEvent: eventAdapter.addOne,
+ addEvents: eventAdapter.addMany,
+ upsertEvent: eventAdapter.upsertOne, // Add or Update
+ },
+});
+export const { addEvent, addEvents, upsertEvent } = grlEventsSlice.actions;
export const eventSelectors = eventAdapter.getSelectors(
- (state: RootState) => state.events
+ (state: RootState) => state.events,
);
-export const selectAllEvents = (state: RootState): EventEnvelope[] => eventSelectors.selectAll(state);
-
-const BASE_SPEED = 40; // px/sec at idle
-const MAX_SPEED = 380; // px/sec at surge
+export const selectAllEvents = (state: RootState): EventEnvelope[] =>
+ eventSelectors.selectAll(state);
-const RATE_WINDOW_MS = 10_000; // ms window to measure message frequency
-const RATE_TO_SPEED = 55; // px/sec added per msg/sec
+const BASE_SPEED = 40; // px/sec at idle
+const MAX_SPEED = 380; // px/sec at surge
+const RATE_WINDOW_MS = 10_000; // ms window to measure message frequency
+const RATE_TO_SPEED = 55; // px/sec added per msg/sec
-// --- Speed: derived from arrival rate of recent items ---
+// --- Speed: derived from arrival rate of recent items ---
export const selectCurrentSpeed = createSelector(selectAllEvents, (items) => {
- const now = Date.now();
+ const now = Date.now();
- const recentCount = items.filter((m) => {
- const ts = new Date(m.timestamp!).getTime();
- return now - ts < RATE_WINDOW_MS;
- }).length;
+ const recentCount = items.filter((m) => {
+ const ts = new Date(m.timestamp!).getTime();
+ return now - ts < RATE_WINDOW_MS;
+ }).length;
- const rate = recentCount / (RATE_WINDOW_MS / 1_000); // msgs/sec
- return Math.min(BASE_SPEED + rate * RATE_TO_SPEED, MAX_SPEED);
+ const rate = recentCount / (RATE_WINDOW_MS / 1_000); // msgs/sec
+ return Math.min(BASE_SPEED + rate * RATE_TO_SPEED, MAX_SPEED);
});
-export default grlEventsSlice.reducer
+export default grlEventsSlice.reducer;
diff --git a/jb-ui/src/models/grlStatsSlice.ts b/jb-ui/src/models/grlStatsSlice.ts
index 9385256..004d321 100644
--- a/jb-ui/src/models/grlStatsSlice.ts
+++ b/jb-ui/src/models/grlStatsSlice.ts
@@ -1,54 +1,47 @@
import { StatsSnapshot } from "@/api_fsb";
import { RootState } from "@/store";
-import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit";
-
-const initialState: StatsSnapshot[] = []
+const initialState: StatsSnapshot[] = [];
const grlStatsSlice = createSlice({
- name: 'grlStats',
- initialState,
- reducers: {
-
- addStatsData(state, action: PayloadAction<StatsSnapshot>) {
- state.push(action.payload);
- }
- }
-})
-
-export const {
- addStatsData
-} = grlStatsSlice.actions;
-export default grlStatsSlice.reducer
-
+ name: "grlStats",
+ initialState,
+ reducers: {
+ addStatsData(state, action: PayloadAction<StatsSnapshot>) {
+ state.push(action.payload);
+ },
+ },
+});
+
+export const { addStatsData } = grlStatsSlice.actions;
+export default grlStatsSlice.reducer;
export const selectRecentStats = createSelector(
- [
- (state: RootState) => state.stats,
- ],
- (stats): StatsSnapshot | null => {
- const lastStat = stats[stats.length - 1];
- return lastStat ?? null;
- }
+ [(state: RootState) => state.stats],
+ (stats): StatsSnapshot | null => {
+ const lastStat = stats[stats.length - 1];
+ return lastStat ?? null;
+ },
);
export const activeUsers = createSelector(
- [selectRecentStats],
- (recentStats): number | null => {
- return recentStats?.active_users_last_24h ?? null;
- }
+ [selectRecentStats],
+ (recentStats): number | null => {
+ return recentStats?.active_users_last_24h ?? null;
+ },
);
export const activeSurveys = createSelector(
- [selectRecentStats],
- (recentStats): number | null => {
- return recentStats?.live_task_count?.total ?? null;
- }
+ [selectRecentStats],
+ (recentStats): number | null => {
+ return recentStats?.live_task_count?.total ?? null;
+ },
);
export const maxPayout = createSelector(
- [selectRecentStats],
- (recentStats): number | null => {
- return recentStats?.live_tasks_max_payout?.value ?? null;
- }
+ [selectRecentStats],
+ (recentStats): number | null => {
+ return recentStats?.live_tasks_max_payout?.value ?? null;
+ },
);
diff --git a/jb-ui/src/models/profilingQuestionsSlice.ts b/jb-ui/src/models/profilingQuestionsSlice.ts
index cc36f17..577566f 100644
--- a/jb-ui/src/models/profilingQuestionsSlice.ts
+++ b/jb-ui/src/models/profilingQuestionsSlice.ts
@@ -1,313 +1,327 @@
import {
- BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost,
- ProfilingQuestionsApi,
- StatusResponse,
- UpkQuestion, UserQuestionAnswerIn
+ BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost,
+ ProfilingQuestionsApi,
+ StatusResponse,
+ UpkQuestion,
+ UserQuestionAnswerIn,
} from "@/api_fsb";
import { assert, bpid } from "@/lib/utils";
import { questionUtils } from "@/models/profilingUtils";
-import type { RootState } from '@/store';
+import type { RootState } from "@/store";
import {
- createAsyncThunk,
- createEntityAdapter, createSlice,
- PayloadAction,
- WritableDraft
-} from '@reduxjs/toolkit';
+ createAsyncThunk,
+ createEntityAdapter,
+ createSlice,
+ PayloadAction,
+ WritableDraft,
+} from "@reduxjs/toolkit";
interface UpkQuestionMetadata {
- // The data we need to conduct profiling questions and manager user
- // submission along with the User Interfaces
+ // The data we need to conduct profiling questions and manager user
+ // submission along with the User Interfaces
- // Only one Question can be active at a time, which is the one
- // being shown to the Respondent
- isActive: boolean;
+ // Only one Question can be active at a time, which is the one
+ // being shown to the Respondent
+ isActive: boolean;
- answers: string[];
+ answers: string[];
- // If it's actively being submitted to the server
- isProcessing: boolean;
+ // If it's actively being submitted to the server
+ isProcessing: boolean;
- // If we recieved a successful response from the server after submitting
- isSaved: boolean;
+ // If we recieved a successful response from the server after submitting
+ isSaved: boolean;
}
interface ValidationResult {
- // If isValid or isComplete are undefined, that means the question
- // hasn't been validated yet. This is different from false, which means
- // it has been validated and is not valid.
- isValid?: boolean;
- isComplete?: boolean;
- errors: ValidationError[];
-};
+ // If isValid or isComplete are undefined, that means the question
+ // hasn't been validated yet. This is different from false, which means
+ // it has been validated and is not valid.
+ isValid?: boolean;
+ isComplete?: boolean;
+ errors: ValidationError[];
+}
export interface ValidationError {
- path: string; // e.g., "user.email"
- message: string;
- severity: 'error' | 'warning';
-};
+ path: string; // e.g., "user.email"
+ message: string;
+ severity: "error" | "warning";
+}
export interface ProfileQuestion extends UpkQuestion {
- _metadata: UpkQuestionMetadata;
- _validation: ValidationResult;
+ _metadata: UpkQuestionMetadata;
+ _validation: ValidationResult;
}
// Entity adapter for normalized storage
const questionsAdapter = createEntityAdapter({
- selectId: (model: ProfileQuestion) => model.question_id!,
- sortComparer: (a, b) => {
- return (b.importance?.task_score ?? 0) - (a.importance?.task_score ?? 0);
- },
+ selectId: (model: ProfileQuestion) => model.question_id!,
+ sortComparer: (a, b) => {
+ return (b.importance?.task_score ?? 0) - (a.importance?.task_score ?? 0);
+ },
});
-
function getDefaultMetadata(): UpkQuestionMetadata {
- return {
- isActive: false,
- answers: [],
- isProcessing: false,
- isSaved: false,
- };
+ return {
+ isActive: false,
+ answers: [],
+ isProcessing: false,
+ isSaved: false,
+ };
}
function getDefaultValidation(): ValidationResult {
-
- return {
- isValid: undefined,
- isComplete: undefined,
- errors: [],
- };
+ return {
+ isValid: undefined,
+ isComplete: undefined,
+ errors: [],
+ };
}
// Create the async thunk (outside your slice)
export const saveAnswer = createAsyncThunk(
- 'profilingQuestions/saveAnswer',
- async ({ questionId, bpuid }: { questionId: string; bpuid: string }, { getState, dispatch }) => {
- const state = getState() as RootState;
- const question = state.profilingQuestions.entities[questionId];
-
- // Validations
- const answers = {
- 'question_id': question.question_id!,
- 'answer': question._metadata.answers
- } as UserQuestionAnswerIn;
-
- const answers_body = {
- 'answers': [answers]
- } as BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost;
-
- // Make API call
- const res = await new ProfilingQuestionsApi()
- .submitProfilingQuestionsProductIdProfilingQuestionsPost(
- bpid,
- bpuid,
- answers_body,
- undefined,
- true
- );
-
- const response = res.data as StatusResponse;
-
- // Check if we need to fetch new questions BEFORE returning
- if (response.status === "success" && isFirstNonGR(state.profilingQuestions)) {
- // NOW dispatch it
- dispatch(fetchNewQuestions(bpuid));
- }
-
- return { questionId, response };
-
+ "profilingQuestions/saveAnswer",
+ async (
+ { questionId, bpuid }: { questionId: string; bpuid: string },
+ { getState, dispatch },
+ ) => {
+ const state = getState() as RootState;
+ const question = state.profilingQuestions.entities[questionId];
+
+ // Validations
+ const answers = {
+ question_id: question.question_id!,
+ answer: question._metadata.answers,
+ } as UserQuestionAnswerIn;
+
+ const answers_body = {
+ answers: [answers],
+ } as BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost;
+
+ // Make API call
+ const res =
+ await new ProfilingQuestionsApi().submitProfilingQuestionsProductIdProfilingQuestionsPost(
+ bpid,
+ bpuid,
+ answers_body,
+ undefined,
+ true,
+ );
+
+ const response = res.data as StatusResponse;
+
+ // Check if we need to fetch new questions BEFORE returning
+ if (
+ response.status === "success" &&
+ isFirstNonGR(state.profilingQuestions)
+ ) {
+ // NOW dispatch it
+ dispatch(fetchNewQuestions(bpuid));
}
-)
-export const fetchNewQuestions = createAsyncThunk(
- 'profilingQuestions/fetchNewQuestions',
- async (bpuid: string) => {
-
- console.log("profilingQuestions/fetchNewQuestions")
- const res = await new ProfilingQuestionsApi()
- .getProfilingQuestionsProductIdProfilingQuestionsGet(
- bpid,
- bpuid,
- undefined, // "104.9.125.144", // ip
- undefined, // countryIso
- undefined, // languageIso
- 2_500
- );
- return res.data.questions;
- }
+ return { questionId, response };
+ },
);
-type ProfilingQuestionsState = ReturnType<typeof profilingQuestionSlice.getInitialState>;
+export const fetchNewQuestions = createAsyncThunk(
+ "profilingQuestions/fetchNewQuestions",
+ async (bpuid: string) => {
+ console.log("profilingQuestions/fetchNewQuestions");
+ const res =
+ await new ProfilingQuestionsApi().getProfilingQuestionsProductIdProfilingQuestionsGet(
+ bpid,
+ bpuid,
+ undefined, // "104.9.125.144", // ip
+ undefined, // countryIso
+ undefined, // languageIso
+ 2_500,
+ );
+ return res.data.questions;
+ },
+);
+type ProfilingQuestionsState = ReturnType<
+ typeof profilingQuestionSlice.getInitialState
+>;
// Helper function that contains the logic (outside the slice)
function goToNextQuestionLogic(state: WritableDraft<ProfilingQuestionsState>) {
- const allQuestions = questionsAdapter.getSelectors().selectAll(state);
- const currentIndex = allQuestions.findIndex(q => q._metadata.isActive);
-
- if (currentIndex === -1) return;
-
- const totalQuestions = allQuestions.length;
- let searchIndex = (currentIndex + 1) % totalQuestions;
- let iterations = 0;
-
- while (iterations < totalQuestions) {
- if (!allQuestions[searchIndex]._metadata.isSaved) {
- questionsAdapter.updateMany(state, [
- {
- id: allQuestions[currentIndex].question_id!,
- changes: {
- _metadata: {
- ...allQuestions[currentIndex]._metadata,
- isActive: false
- }
- }
- },
- {
- id: allQuestions[searchIndex].question_id!,
- changes: {
- _metadata: {
- ...allQuestions[searchIndex]._metadata,
- isActive: true
- }
- }
- }
- ]);
- return;
- }
-
- searchIndex = (searchIndex + 1) % totalQuestions;
- iterations++;
+ const allQuestions = questionsAdapter.getSelectors().selectAll(state);
+ const currentIndex = allQuestions.findIndex((q) => q._metadata.isActive);
+
+ if (currentIndex === -1) return;
+
+ const totalQuestions = allQuestions.length;
+ let searchIndex = (currentIndex + 1) % totalQuestions;
+ let iterations = 0;
+
+ while (iterations < totalQuestions) {
+ if (!allQuestions[searchIndex]._metadata.isSaved) {
+ questionsAdapter.updateMany(state, [
+ {
+ id: allQuestions[currentIndex].question_id!,
+ changes: {
+ _metadata: {
+ ...allQuestions[currentIndex]._metadata,
+ isActive: false,
+ },
+ },
+ },
+ {
+ id: allQuestions[searchIndex].question_id!,
+ changes: {
+ _metadata: {
+ ...allQuestions[searchIndex]._metadata,
+ isActive: true,
+ },
+ },
+ },
+ ]);
+ return;
}
+
+ searchIndex = (searchIndex + 1) % totalQuestions;
+ iterations++;
+ }
}
function setProfilingQuestionsLogic(
- state: WritableDraft<ProfilingQuestionsState>,
- questions: ProfileQuestion[]) {
-
- const hasActiveQuestion = Object.values(state.entities).some(
- entity => entity?._metadata.isActive
- );
-
- const entities = questions.map((serverQuestion, index) => {
- const existing = state.entities[serverQuestion.question_id!];
- const shouldActivate = !hasActiveQuestion && index === 0;
-
- return {
- ...serverQuestion,
- _metadata: existing?._metadata || {
- ...getDefaultMetadata(),
- isActive: shouldActivate,
- },
- _validation: existing?._validation || getDefaultValidation(),
- };
- });
+ state: WritableDraft<ProfilingQuestionsState>,
+ questions: ProfileQuestion[],
+) {
+ const hasActiveQuestion = Object.values(state.entities).some(
+ (entity) => entity?._metadata.isActive,
+ );
- questionsAdapter.setAll(state, entities);
-}
+ const entities = questions.map((serverQuestion, index) => {
+ const existing = state.entities[serverQuestion.question_id!];
+ const shouldActivate = !hasActiveQuestion && index === 0;
+ return {
+ ...serverQuestion,
+ _metadata: existing?._metadata || {
+ ...getDefaultMetadata(),
+ isActive: shouldActivate,
+ },
+ _validation: existing?._validation || getDefaultValidation(),
+ };
+ });
+
+ questionsAdapter.setAll(state, entities);
+}
function isGR(ext_question_id: string): boolean {
- return ext_question_id.startsWith("gr:")
+ return ext_question_id.startsWith("gr:");
}
function isFirstNonGR(state: WritableDraft<ProfilingQuestionsState>): boolean {
- // We want to identify if the next question is the first non-GR question
- // because will want to trigger a full profile question refresh.
+ // We want to identify if the next question is the first non-GR question
+ // because will want to trigger a full profile question refresh.
- const allQuestions = questionsAdapter.getSelectors().selectAll(state);
- const currentIndex = allQuestions.findIndex(q => q._metadata.isActive);
+ const allQuestions = questionsAdapter.getSelectors().selectAll(state);
+ const currentIndex = allQuestions.findIndex((q) => q._metadata.isActive);
- if (currentIndex === -1) false;
+ if (currentIndex === -1) false;
- const totalQuestions = allQuestions.length;
- let searchIndex = (currentIndex + 1) % totalQuestions;
- let iterations = 0;
+ const totalQuestions = allQuestions.length;
+ let searchIndex = (currentIndex + 1) % totalQuestions;
+ let iterations = 0;
- while (iterations < totalQuestions) {
- if (!allQuestions[searchIndex]._metadata.isSaved) {
+ while (iterations < totalQuestions) {
+ if (!allQuestions[searchIndex]._metadata.isSaved) {
+ const current = isGR(allQuestions[currentIndex].ext_question_id!);
+ const next = isGR(allQuestions[searchIndex].ext_question_id!);
- const current = isGR(allQuestions[currentIndex].ext_question_id!)
- const next = isGR(allQuestions[searchIndex].ext_question_id!)
-
- // We want to identify transitions from GR to non-GR questions,
- // as we use GR questions to pre-calculate some non-GR questions,
- // we should force a refresh.
- return current && !next;
- }
-
- searchIndex = (searchIndex + 1) % totalQuestions;
- iterations++;
+ // We want to identify transitions from GR to non-GR questions,
+ // as we use GR questions to pre-calculate some non-GR questions,
+ // we should force a refresh.
+ return current && !next;
}
- return false;
+ searchIndex = (searchIndex + 1) % totalQuestions;
+ iterations++;
+ }
+
+ return false;
}
const profilingQuestionSlice = createSlice({
- name: 'profilingQuestions',
- initialState: questionsAdapter.getInitialState(),
- reducers: {
+ name: "profilingQuestions",
+ initialState: questionsAdapter.getInitialState(),
+ reducers: {
+ setProfilingQuestions: (
+ state,
+ action: PayloadAction<ProfileQuestion[]>,
+ ) => {
+ setProfilingQuestionsLogic(state, action.payload);
+ },
- setProfilingQuestions: (state, action: PayloadAction<ProfileQuestion[]>) => {
- setProfilingQuestionsLogic(state, action.payload);
- },
+ metadataUpdated: (
+ state,
+ action: PayloadAction<{
+ question_id: string;
+ metadata: Partial<UpkQuestionMetadata>;
+ }>,
+ ) => {
+ const { question_id, metadata } = action.payload;
+ const entity = state.entities[question_id];
+ if (entity) {
+ entity._metadata = { ...entity._metadata, ...metadata };
+ }
+ },
- metadataUpdated: (
- state,
- action: PayloadAction<{ question_id: string; metadata: Partial<UpkQuestionMetadata> }>
- ) => {
- const { question_id, metadata } = action.payload;
- const entity = state.entities[question_id];
- if (entity) {
- entity._metadata = { ...entity._metadata, ...metadata };
- }
- },
+ validationUpdated: (
+ state,
+ action: PayloadAction<{
+ question_id: string;
+ validation: Partial<ValidationResult>;
+ }>,
+ ) => {
+ const { question_id, validation } = action.payload;
+ const entity = state.entities[question_id];
+ if (entity) {
+ entity._validation = { ...entity._validation, ...validation };
+ }
+ },
- validationUpdated: (
- state,
- action: PayloadAction<{ question_id: string; validation: Partial<ValidationResult> }>
- ) => {
- const { question_id, validation } = action.payload;
- const entity = state.entities[question_id];
- if (entity) {
- entity._validation = { ...entity._validation, ...validation };
- }
- },
+ // Set one question as active, deactivate all others
+ setActiveQuestion: (state, action: PayloadAction<string>) => {
+ const questionId = action.payload;
- // Set one question as active, deactivate all others
- setActiveQuestion: (state, action: PayloadAction<string>) => {
- const questionId = action.payload;
-
- // Deactivate all questions
- Object.values(state.entities).forEach(entity => {
- if (entity) {
- entity._metadata.isActive = false;
- }
- });
-
- // Activate the selected one
- const entity = state.entities[questionId];
- if (entity) {
- entity._metadata.isActive = true;
- }
- },
+ // Deactivate all questions
+ Object.values(state.entities).forEach((entity) => {
+ if (entity) {
+ entity._metadata.isActive = false;
+ }
+ });
- // Clear active state from all questions
- clearActiveQuestion: (state) => {
- Object.values(state.entities).forEach(entity => {
- if (entity) {
- entity._metadata.isActive = false;
- }
- });
- },
+ // Activate the selected one
+ const entity = state.entities[questionId];
+ if (entity) {
+ entity._metadata.isActive = true;
+ }
+ },
- goToNextQuestion: (state) => {
- goToNextQuestionLogic(state);
- },
+ // Clear active state from all questions
+ clearActiveQuestion: (state) => {
+ Object.values(state.entities).forEach((entity) => {
+ if (entity) {
+ entity._metadata.isActive = false;
+ }
+ });
+ },
+
+ goToNextQuestion: (state) => {
+ goToNextQuestionLogic(state);
+ },
- // -----------------------
+ // -----------------------
- addAnswers(state, action: PayloadAction<{ questionId: string, answers: string[] }>) {
- /* When changing the answers in anyway, we want to:
+ addAnswers(
+ state,
+ action: PayloadAction<{ questionId: string; answers: string[] }>,
+ ) {
+ /* When changing the answers in anyway, we want to:
1. Add the new answers to the question metadata
This does not perform validation, it simply reassigns
@@ -325,112 +339,124 @@ const profilingQuestionSlice = createSlice({
3. Re-calculate the isComplete and isValid state
*/
- // let new_question = questionUtils.addAnswer(action.payload.question, action.payload.answers)
- let entity = state.entities[action.payload.questionId];
- const newMetadata = { ...entity._metadata, answers: action.payload.answers };
+ // let new_question = questionUtils.addAnswer(action.payload.question, action.payload.answers)
+ let entity = state.entities[action.payload.questionId];
+ const newMetadata = {
+ ...entity._metadata,
+ answers: action.payload.answers,
+ };
- if (entity) {
- entity._metadata = newMetadata;
+ if (entity) {
+ entity._metadata = newMetadata;
- entity = questionUtils.validate(entity)
- entity = questionUtils.assignValidationState(entity)
+ entity = questionUtils.validate(entity);
+ entity = questionUtils.assignValidationState(entity);
- state.entities[action.payload.questionId] = entity
- }
- },
+ state.entities[action.payload.questionId] = entity;
+ }
},
-
- extraReducers: (builder) => {
- builder
- .addCase(saveAnswer.pending, (state, action) => {
- const questionId = action.meta.arg.questionId;
- const bpuid = action.meta.arg.bpuid;
- assert(bpuid, "Worker must be defined");
-
- const question = state.entities[questionId];
- if (question) {
- assert(question._validation.isComplete, "Must submit Completed Questions");
- assert(!question._metadata.isProcessing, "Can't submit processing Answer");
- assert(!question._metadata.isSaved, "Can't submit completed Answer");
- question._metadata.isProcessing = true;
- }
- })
- .addCase(saveAnswer.fulfilled, (state, action) => {
- const { questionId, response } = action.payload;
- const question = state.entities[questionId];
-
- if (question) {
- question._metadata.isProcessing = false;
- if (response.status === "success") {
- question._metadata.isSaved = true;
-
- // fetchNewQuestions is already being dispatched from
- // the THUNK
- goToNextQuestionLogic(state);
-
- } else {
- question._metadata.isSaved = false;
- }
- }
- })
- .addCase(saveAnswer.rejected, (state, action) => {
- const questionId = action.meta.arg.questionId;
- const question = state.entities[questionId];
-
- if (question) {
- question._metadata.isProcessing = false;
- question._metadata.isSaved = false;
- }
- })
- .addCase(fetchNewQuestions.fulfilled, (state, action) => {
- console.log(".addCase(fetchNewQuestions.fulfilled, (state, action) => {")
- setProfilingQuestionsLogic(state, action.payload as ProfileQuestion[]);
- });
- ;
- }
-
-})
+ },
+
+ extraReducers: (builder) => {
+ builder
+ .addCase(saveAnswer.pending, (state, action) => {
+ const questionId = action.meta.arg.questionId;
+ const bpuid = action.meta.arg.bpuid;
+ assert(bpuid, "Worker must be defined");
+
+ const question = state.entities[questionId];
+ if (question) {
+ assert(
+ question._validation.isComplete,
+ "Must submit Completed Questions",
+ );
+ assert(
+ !question._metadata.isProcessing,
+ "Can't submit processing Answer",
+ );
+ assert(!question._metadata.isSaved, "Can't submit completed Answer");
+ question._metadata.isProcessing = true;
+ }
+ })
+ .addCase(saveAnswer.fulfilled, (state, action) => {
+ const { questionId, response } = action.payload;
+ const question = state.entities[questionId];
+
+ if (question) {
+ question._metadata.isProcessing = false;
+ if (response.status === "success") {
+ question._metadata.isSaved = true;
+
+ // fetchNewQuestions is already being dispatched from
+ // the THUNK
+ goToNextQuestionLogic(state);
+ } else {
+ question._metadata.isSaved = false;
+ }
+ }
+ })
+ .addCase(saveAnswer.rejected, (state, action) => {
+ const questionId = action.meta.arg.questionId;
+ const question = state.entities[questionId];
+
+ if (question) {
+ question._metadata.isProcessing = false;
+ question._metadata.isSaved = false;
+ }
+ })
+ .addCase(fetchNewQuestions.fulfilled, (state, action) => {
+ console.log(
+ ".addCase(fetchNewQuestions.fulfilled, (state, action) => {",
+ );
+ setProfilingQuestionsLogic(state, action.payload as ProfileQuestion[]);
+ });
+ },
+});
export const {
- setProfilingQuestions,
- metadataUpdated,
- setActiveQuestion,
- goToNextQuestion,
- addAnswers,
+ setProfilingQuestions,
+ metadataUpdated,
+ setActiveQuestion,
+ goToNextQuestion,
+ addAnswers,
} = profilingQuestionSlice.actions;
// Selectors
export const questionsSelectors = questionsAdapter.getSelectors(
- (state: RootState) => state.profilingQuestions
+ (state: RootState) => state.profilingQuestions,
);
// Custom selector to get the active question
export const selectAllQuestions = (state: RootState): ProfileQuestion[] => {
- return questionsSelectors.selectAll(state) ?? [];
+ return questionsSelectors.selectAll(state) ?? [];
};
// Custom selector to get the active question
-export const selectActiveQuestion = (state: RootState): ProfileQuestion | null => {
- const allQuestions = questionsSelectors.selectAll(state);
- return allQuestions.find(q => q._metadata.isActive) || null;
+export const selectActiveQuestion = (
+ state: RootState,
+): ProfileQuestion | null => {
+ const allQuestions = questionsSelectors.selectAll(state);
+ return allQuestions.find((q) => q._metadata.isActive) || null;
};
// Custom selector to get active question ID
export const selectActiveQuestionId = (state: RootState): string | null => {
- const activeQuestion = selectActiveQuestion(state);
- return activeQuestion?.question_id || null;
+ const activeQuestion = selectActiveQuestion(state);
+ return activeQuestion?.question_id || null;
};
-export const selectActiveQuestionMetadata = (state: RootState): UpkQuestionMetadata | null => {
- const activeQuestion = selectActiveQuestion(state);
- return activeQuestion?._metadata || null;
+export const selectActiveQuestionMetadata = (
+ state: RootState,
+): UpkQuestionMetadata | null => {
+ const activeQuestion = selectActiveQuestion(state);
+ return activeQuestion?._metadata || null;
};
-export const selectActiveQuestionValidation = (state: RootState): ValidationResult | null => {
- const activeQuestion = selectActiveQuestion(state);
- return activeQuestion?._validation || null;
+export const selectActiveQuestionValidation = (
+ state: RootState,
+): ValidationResult | null => {
+ const activeQuestion = selectActiveQuestion(state);
+ return activeQuestion?._validation || null;
};
-
-export default profilingQuestionSlice.reducer
-
+export default profilingQuestionSlice.reducer;
diff --git a/jb-ui/src/models/profilingUtils.ts b/jb-ui/src/models/profilingUtils.ts
index 104a5bb..a3ef7d2 100644
--- a/jb-ui/src/models/profilingUtils.ts
+++ b/jb-ui/src/models/profilingUtils.ts
@@ -1,29 +1,36 @@
-import { PatternValidation, UpkQuestionConfigurationMC, UpkQuestionConfigurationTE } from "@/api_fsb";
+import {
+ PatternValidation,
+ UpkQuestionConfigurationMC,
+ UpkQuestionConfigurationTE,
+} from "@/api_fsb";
import { assert } from "@/lib/utils";
-import { ProfileQuestion, ValidationError } from '@/models/profilingQuestionsSlice';
-import { Filter } from 'bad-words';
+import {
+ ProfileQuestion,
+ ValidationError,
+} from "@/models/profilingQuestionsSlice";
+import { Filter } from "bad-words";
const filter = new Filter();
export const questionUtils = {
-
- assignValidationState: (question: ProfileQuestion): ProfileQuestion => {
- /* This function performs validation on the question's current answers and
+ assignValidationState: (question: ProfileQuestion): ProfileQuestion => {
+ /* This function performs validation on the question's current answers and
assigns any error messages to question._metadata.error_msg.
If the question is MC, validate:
*/
- const errors = question._validation.errors ?? []
+ const errors = question._validation.errors ?? [];
- question._validation.isComplete = errors.length === 0
- question._validation.isValid = errors.filter(e => e.severity === 'error').length === 0
+ question._validation.isComplete = errors.length === 0;
+ question._validation.isValid =
+ errors.filter((e) => e.severity === "error").length === 0;
- return question;
- },
+ return question;
+ },
- validate: (question: ProfileQuestion): ProfileQuestion => {
- /* If the question is MC, validate:
+ validate: (question: ProfileQuestion): ProfileQuestion => {
+ /* If the question is MC, validate:
- validate selector SA vs MA (1 selected vs >1 selected)
- the answers match actual codes in the choices
@@ -35,121 +42,132 @@ export const questionUtils = {
- validation.patterns
*/
- assert(question.question_id, "Question must have question_id")
- // assert(question.configuration, "Question must have configuration")
- const answers = question._metadata.answers ?? []
-
- // Declare it here, and they we'll reassign any specific
- // configuration types based on the question type.
-
- // Start fresh without any error messages before validating
- const errors: ValidationError[] = []
-
- switch (question.question_type) {
- case "TE":
-
- answers.length === 0 && errors.push({
- path: `question_id:${question.question_id}`,
- message: "No answer provided",
- severity: "warning",
- } as ValidationError)
-
- answers.length > 1 && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Only one answer allowed",
- severity: "error",
- } as ValidationError)
-
- let answer_text: string = answers[0]
-
- const te_config = question.configuration as UpkQuestionConfigurationTE
- const min_length = te_config.min_length ?? 0
- const max_length = te_config.max_length ?? 100_000
-
- answer_text.length < min_length && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Answer shorter than allowed",
- severity: "warning",
- } as ValidationError)
-
- answer_text.length > max_length && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Answer longer than allowed",
- severity: "error",
- } as ValidationError)
-
- filter.isProfane(answer_text) && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Answer has inappropriate content",
- severity: "error",
- } as ValidationError)
-
- const patterns: PatternValidation[] = (question.validation ?? {})["patterns"] ?? []
- patterns.forEach((pv) => {
- let re = new RegExp(pv.pattern)
- answer_text.search(re) == -1 && errors.push({
- path: `question_id:${question.question_id}`,
- message: pv.message,
- severity: "error",
- } as ValidationError)
-
- })
-
- break;
-
- case "MC":
-
- answers.length === 0 && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Multiple Choice question with no selected answers",
- severity: "warning",
- } as ValidationError)
-
- const choice_codes: string[] = question.choices?.map((c) => c.choice_id) ?? [];
-
- const mc_config = (question.configuration ?? {}) as UpkQuestionConfigurationMC
- const max_select = mc_config.max_select ?? choice_codes.length
-
- switch (question.selector) {
- case "SA":
- answers.length > 1 && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Single Answer MC question with >1 selected answers",
- severity: "error",
- } as ValidationError)
-
- break;
-
- case "MA":
- answers.length > max_select && errors.push({
- path: `question_id:${question.question_id}`,
- message: "More options selected than allowed",
- severity: "error",
- } as ValidationError)
-
- answers.length === max_select && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Selected all the options",
- severity: "error",
- } as ValidationError)
-
- break;
- }
-
- // Now validate Multiple Choice answers regardless of if
- // they're Single Answer (SA) or Multiple Answer (MA)
- !answers.every(item => choice_codes.includes(item)) && errors.push({
- path: `question_id:${question.question_id}`,
- message: "Invalid options selected",
- severity: "error",
- })
-
- // const max_select: number = question.configuration?.max_select ?? choice_codes.length
- // if (answer.values.length > max_select) {
- // answer.error_msg = "More options selected than allowed"
- // }
-
- /*
+ assert(question.question_id, "Question must have question_id");
+ // assert(question.configuration, "Question must have configuration")
+ const answers = question._metadata.answers ?? [];
+
+ // Declare it here, and they we'll reassign any specific
+ // configuration types based on the question type.
+
+ // Start fresh without any error messages before validating
+ const errors: ValidationError[] = [];
+
+ switch (question.question_type) {
+ case "TE":
+ answers.length === 0 &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "No answer provided",
+ severity: "warning",
+ } as ValidationError);
+
+ answers.length > 1 &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Only one answer allowed",
+ severity: "error",
+ } as ValidationError);
+
+ let answer_text: string = answers[0];
+
+ const te_config = question.configuration as UpkQuestionConfigurationTE;
+ const min_length = te_config.min_length ?? 0;
+ const max_length = te_config.max_length ?? 100_000;
+
+ answer_text.length < min_length &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Answer shorter than allowed",
+ severity: "warning",
+ } as ValidationError);
+
+ answer_text.length > max_length &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Answer longer than allowed",
+ severity: "error",
+ } as ValidationError);
+
+ filter.isProfane(answer_text) &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Answer has inappropriate content",
+ severity: "error",
+ } as ValidationError);
+
+ const patterns: PatternValidation[] =
+ (question.validation ?? {})["patterns"] ?? [];
+ patterns.forEach((pv) => {
+ let re = new RegExp(pv.pattern);
+ answer_text.search(re) == -1 &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: pv.message,
+ severity: "error",
+ } as ValidationError);
+ });
+
+ break;
+
+ case "MC":
+ answers.length === 0 &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Multiple Choice question with no selected answers",
+ severity: "warning",
+ } as ValidationError);
+
+ const choice_codes: string[] =
+ question.choices?.map((c) => c.choice_id) ?? [];
+
+ const mc_config = (question.configuration ??
+ {}) as UpkQuestionConfigurationMC;
+ const max_select = mc_config.max_select ?? choice_codes.length;
+
+ switch (question.selector) {
+ case "SA":
+ answers.length > 1 &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Single Answer MC question with >1 selected answers",
+ severity: "error",
+ } as ValidationError);
+
+ break;
+
+ case "MA":
+ answers.length > max_select &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "More options selected than allowed",
+ severity: "error",
+ } as ValidationError);
+
+ answers.length === max_select &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Selected all the options",
+ severity: "error",
+ } as ValidationError);
+
+ break;
+ }
+
+ // Now validate Multiple Choice answers regardless of if
+ // they're Single Answer (SA) or Multiple Answer (MA)
+ !answers.every((item) => choice_codes.includes(item)) &&
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Invalid options selected",
+ severity: "error",
+ });
+
+ // const max_select: number = question.configuration?.max_select ?? choice_codes.length
+ // if (answer.values.length > max_select) {
+ // answer.error_msg = "More options selected than allowed"
+ // }
+
+ /*
exclusive_choice = next((x for x in question["choices"] if x.get("exclusive")), None)
if exclusive_choice:
exclusive_choice_id = exclusive_choice["choice_id"]
@@ -157,21 +175,20 @@ export const questionUtils = {
exclusive_choice_id not in answer, "Invalid exclusive selection"
*/
- break;
-
- default:
- errors.push({
- path: `question_id:${question.question_id}`,
- message: "Incorrect Question Type provided",
- severity: "error",
- } as ValidationError)
- }
-
- // Assign the errors back to the question's _validation field and
- // then return the question
- // TODO: does this edit in place, maybe I don't need to return it
- question._validation.errors = errors
- return question;
- },
-
-}; \ No newline at end of file
+ break;
+
+ default:
+ errors.push({
+ path: `question_id:${question.question_id}`,
+ message: "Incorrect Question Type provided",
+ severity: "error",
+ } as ValidationError);
+ }
+
+ // Assign the errors back to the question's _validation field and
+ // then return the question
+ // TODO: does this edit in place, maybe I don't need to return it
+ question._validation.errors = errors;
+ return question;
+ },
+};
diff --git a/jb-ui/src/pages/Home.tsx b/jb-ui/src/pages/Home.tsx
index 5a5c953..8d509b6 100644
--- a/jb-ui/src/pages/Home.tsx
+++ b/jb-ui/src/pages/Home.tsx
@@ -1,13 +1,7 @@
-import max_lulu from "./max-and-lulu.jpg"
+import max_lulu from "./max-and-lulu.jpg";
const Home = function () {
- return (
- <img
- src={max_lulu}
- alt="Max and Lulu"
- className="object-contain"
- />
- )
+ return <img src={max_lulu} alt="Max and Lulu" className="object-contain" />;
};
-export default Home; \ No newline at end of file
+export default Home;
diff --git a/jb-ui/src/pages/MagicLink.tsx b/jb-ui/src/pages/MagicLink.tsx
new file mode 100644
index 0000000..eb272a6
--- /dev/null
+++ b/jb-ui/src/pages/MagicLink.tsx
@@ -0,0 +1,46 @@
+import { useEffect, useRef, useState } from "react";
+
+type ExchangeState = "working" | "failed" | "missing";
+
+const MagicLink = function () {
+ const started = useRef(false);
+ const [state, setState] = useState<ExchangeState>("working");
+
+ useEffect(() => {
+ // React Strict Mode runs effects twice in development. Never redeem twice.
+ if (started.current) return;
+ started.current = true;
+
+ const params = new URLSearchParams(window.location.search);
+ const token = params.get("token");
+ if (!token) {
+ setState("missing");
+ return;
+ }
+
+ // Keep the credential out of browser history and subsequent Referer headers.
+ window.history.replaceState({}, "", window.location.pathname);
+
+ void fetch("/auth/magic-link/exchange", {
+ method: "POST",
+ credentials: "include",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ token: token }),
+ })
+ .then((response) => {
+ if (!response.ok) throw new Error("Magic-link exchange failed");
+ window.location.replace("/");
+ })
+ .catch(() => setState("failed"));
+ }, []);
+
+ if (state === "missing") {
+ return <p>This login link is missing its token.</p>;
+ }
+ if (state === "failed") {
+ return <p>This login link is invalid or has expired.</p>;
+ }
+ return <p>Signing you in…</p>;
+};
+
+export default MagicLink;
diff --git a/jb-ui/src/pages/Preview.tsx b/jb-ui/src/pages/Preview.tsx
index 153b4bb..c58a85e 100644
--- a/jb-ui/src/pages/Preview.tsx
+++ b/jb-ui/src/pages/Preview.tsx
@@ -1,287 +1,394 @@
import {
- Leaderboard,
- LeaderboardApi,
- LeaderboardCode,
- LeaderboardFrequency,
- LeaderboardRow,
+ Leaderboard,
+ LeaderboardApi,
+ LeaderboardCode,
+ LeaderboardFrequency,
+ LeaderboardRow,
} from "@/api_fsb";
import { useAppSelector } from "@/hooks";
-import { bpid, formatCentsToUSD, truncate, } from "@/lib/utils";
+import { bpid, formatCentsToUSD, truncate } from "@/lib/utils";
import { activeSurveys, activeUsers, maxPayout } from "@/models/grlStatsSlice";
import { clsx } from "clsx";
-import moment from 'moment';
-import { useEffect, useState } from 'react';
+import moment from "moment";
+import { FormEvent, useEffect, useState } from "react";
const showSmartRank = (
- item: LeaderboardRow,
- index: number,
- items: LeaderboardRow[] | undefined
+ item: LeaderboardRow,
+ index: number,
+ items: LeaderboardRow[] | undefined,
): boolean => {
- /**
- * Smart rank calculation - this determines if we should show the rank
- * value. It's confusing to show people that multiple individuals ranked
- * in the same place, so this will only display the next ranked value, eg:
- *
- * - 1st
- * - ___
- * - 3rd
- * - ___
- * - ___
- * - 6th
- *
- * @returns number
- */
- if (!items) return false;
-
- const thisRank = item.rank;
- if (index >= 1) {
- const prevRank = items[index - 1].rank;
- if (thisRank === prevRank) {
- return false;
- }
+ /**
+ * Smart rank calculation - this determines if we should show the rank
+ * value. It's confusing to show people that multiple individuals ranked
+ * in the same place, so this will only display the next ranked value, eg:
+ *
+ * - 1st
+ * - ___
+ * - 3rd
+ * - ___
+ * - ___
+ * - 6th
+ *
+ * @returns number
+ */
+ if (!items) return false;
+
+ const thisRank = item.rank;
+ if (index >= 1) {
+ const prevRank = items[index - 1].rank;
+ if (thisRank === prevRank) {
+ return false;
}
- return true;
+ }
+ return true;
};
interface FrequencyButtonsProps {
- selected: LeaderboardFrequency;
- onChange: (frequency: LeaderboardFrequency) => void;
+ selected: LeaderboardFrequency;
+ onChange: (frequency: LeaderboardFrequency) => void;
}
const frequency_map = [
- { label: 'Day', value: LeaderboardFrequency.Daily },
- { label: 'Week', value: LeaderboardFrequency.Weekly },
- { label: 'Month', value: LeaderboardFrequency.Monthly },
+ { label: "Day", value: LeaderboardFrequency.Daily },
+ { label: "Week", value: LeaderboardFrequency.Weekly },
+ { label: "Month", value: LeaderboardFrequency.Monthly },
];
const ThreeButtonToggle = ({ selected, onChange }: FrequencyButtonsProps) => {
- return (
- <div className="inline-flex rounded shadow-sm" role="group">
- {frequency_map.map((button, idx) => (
- <button
- type="button"
- key={button.value}
- onClick={() => onChange(button.value)}
- className={clsx(
- "px-2 py-1 text-[10px] font-medium",
- "border-t border-b border-gray-200",
- "hover:cursor-pointer hover:bg-zinc-200 hover:text-zinc-950",
- idx === 0 && "rounded-l",
- idx === frequency_map.length - 1 && "rounded-r",
- selected === button.value
- ? 'text-zinc-50 bg-zinc-400'
- : 'text-zinc-950 bg-zinc-50',
- )}>
- {button.label}
- </button>
- ))}
- </div>
- );
+ return (
+ <div className="inline-flex rounded shadow-sm" role="group">
+ {frequency_map.map((button, idx) => (
+ <button
+ type="button"
+ key={button.value}
+ onClick={() => onChange(button.value)}
+ className={clsx(
+ "px-2 py-1 text-[10px] font-medium",
+ "border-t border-b border-gray-200",
+ "hover:cursor-pointer hover:bg-zinc-200 hover:text-zinc-950",
+ idx === 0 && "rounded-l",
+ idx === frequency_map.length - 1 && "rounded-r",
+ selected === button.value
+ ? "text-zinc-50 bg-zinc-400"
+ : "text-zinc-950 bg-zinc-50",
+ )}
+ >
+ {button.label}
+ </button>
+ ))}
+ </div>
+ );
};
-
-
// Leaderboards Component
export const Leaderboards = () => {
- /**
- * Leaderboards do not do any caching, or better state management. This is okay because
- * the API is handled to take it. However, it can easily handled better client
- * side rather than making the
- * **/
-
- const [frequency, setFrequency] = useState<LeaderboardFrequency>(
- LeaderboardFrequency.Daily
+ /**
+ * Leaderboards do not do any caching, or better state management. This is okay because
+ * the API is handled to take it. However, it can easily handled better client
+ * side rather than making the
+ * **/
+
+ const [frequency, setFrequency] = useState<LeaderboardFrequency>(
+ LeaderboardFrequency.Daily,
+ );
+
+ const [payouts, setPayouts] = useState<Leaderboard | null>(null);
+ const [completes, setCompletes] = useState<Leaderboard | null>(null);
+
+ const bpuid = undefined;
+
+ useEffect(() => {
+ new LeaderboardApi()
+ .timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(
+ bpid,
+ LeaderboardCode.CompleteCount,
+ frequency,
+ "us",
+ bpuid,
+ undefined, // within_time
+ 10,
+ )
+ .then((res) => {
+ setCompletes(res.data.leaderboard as Leaderboard);
+ });
+
+ new LeaderboardApi()
+ .timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(
+ bpid,
+ LeaderboardCode.SumUserPayout,
+ frequency,
+ "us",
+ bpuid,
+ undefined,
+ 10,
+ )
+ .then((res) => {
+ setPayouts(res.data.leaderboard as Leaderboard);
+ });
+ }, [frequency]);
+
+ let dateRange = " - ";
+ if (completes) {
+ const start = moment(completes?.start_timestamp * 1000).format(
+ "MMM Do, ha",
);
-
- const [payouts, setPayouts] = useState<Leaderboard | null>(null);
- const [completes, setCompletes] = useState<Leaderboard | null>(null);
-
- // const bpuid = useAppSelector(state => state.app.bpuid)
- const bpuid = undefined
-
- useEffect(() => {
- new LeaderboardApi().timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(
- bpid,
- LeaderboardCode.CompleteCount,
- frequency,
- "us",
- bpuid, // bpuid
- undefined, // within_time
- 10)
- .then(res => {
- setCompletes(res.data.leaderboard as Leaderboard)
- })
-
- new LeaderboardApi().timespanLeaderboardProductIdLeaderboardTimespanBoardCodeGet(
- bpid,
- LeaderboardCode.SumUserPayout,
- frequency,
- "us",
- bpuid,
- undefined,
- 10)
- .then(res => {
- setPayouts(res.data.leaderboard as Leaderboard)
- })
- }, [frequency]);
-
- let dateRange = " - "
- if (completes) {
- const start = moment(completes?.start_timestamp * 1000).format("MMM Do, ha");
- const end = moment(completes?.end_timestamp * 1000).format("MMM Do, h:mm:ssa");
- //dateRange = `${start} – ${end} (${completes?.timezone_name})`;
- dateRange = `${start} – ${end}`;
- }
-
- const freq_label = frequency_map.find(f => f.value === frequency)?.label.toLocaleLowerCase()
-
- return (
- <div className="my-2 mx-4 py-0">
- <div className="w-full flex items-center justify-between my-1">
- {/* Left spacer (hidden on small screens) */}
- <div className="hidden md:block md:w-1/3"></div>
-
- {/* Centered text */}
- <h3 className="text-center flex-1 md:1/3">
- Leaderboards
- </h3>
-
- {/* Right-aligned button group */}
- <div className="flex md:w-1/3 justify-end">
- <ThreeButtonToggle
- selected={frequency}
- onChange={setFrequency}
- />
- </div>
- </div>
-
- <div className="grid grid-cols-1 mb-2 text-zinc-700">
- <p className="text-center text-[10px] font-thin">
- {dateRange}
- </p>
- </div>
-
- <div className="grid grid-cols-1 gap-4 px-12 md:px-0
- md:grid-cols-2">
- <table className="border-collapse text-emerald-950 text-[8px] md:text-sm">
- <caption className="caption-top text-xs font-semibold">
- Most earned in the past {freq_label}.
- </caption>
- <thead>
- <tr className="
+ const end = moment(completes?.end_timestamp * 1000).format(
+ "MMM Do, h:mm:ssa",
+ );
+ //dateRange = `${start} – ${end} (${completes?.timezone_name})`;
+ dateRange = `${start} – ${end}`;
+ }
+
+ const freq_label = frequency_map
+ .find((f) => f.value === frequency)
+ ?.label.toLocaleLowerCase();
+
+ return (
+ <div className="my-2 mx-4 py-0">
+ <div className="w-full flex items-center justify-between my-1">
+ {/* Left spacer (hidden on small screens) */}
+ <div className="hidden md:block md:w-1/3"></div>
+
+ {/* Centered text */}
+ <h3 className="text-center flex-1 md:1/3">Leaderboards</h3>
+
+ {/* Right-aligned button group */}
+ <div className="flex md:w-1/3 justify-end">
+ <ThreeButtonToggle selected={frequency} onChange={setFrequency} />
+ </div>
+ </div>
+
+ <div className="grid grid-cols-1 mb-2 text-zinc-700">
+ <p className="text-center text-[10px] font-thin">{dateRange}</p>
+ </div>
+
+ <div
+ className="grid grid-cols-1 gap-4 px-12 md:px-0
+ md:grid-cols-2"
+ >
+ <table className="border-collapse text-emerald-950 text-[8px] md:text-sm">
+ <caption className="caption-top text-xs font-semibold">
+ Most earned in the past {freq_label}.
+ </caption>
+ <thead>
+ <tr
+ className="
font-mono font-semibold text-center
- border border-zinc-150">
- <th>Rank</th>
- <th>Bonus</th>
- <th>User</th>
- </tr>
- </thead>
- <tbody className="font-mono">
-
- {payouts?.rows?.map((dataItem: LeaderboardRow) => (
- <tr key={dataItem.bpuid} className="
+ border border-zinc-150"
+ >
+ <th>Rank</th>
+ <th>Bonus</th>
+ <th>User</th>
+ </tr>
+ </thead>
+ <tbody className="font-mono">
+ {payouts?.rows?.map((dataItem: LeaderboardRow) => (
+ <tr
+ key={dataItem.bpuid}
+ className="
text-center
- border border-zinc-100">
- <td className="font-medium">
- {dataItem.rank}
- </td>
- <td className="font-semibold">
- {formatCentsToUSD(dataItem.value)}
- </td>
- <td className="font-light">
- {truncate(dataItem.bpuid, 6, "*****").toUpperCase()}
- </td>
- </tr>
- ))}
- </tbody>
- </table>
-
- <table className="border-collapse border border-gray-400
- text-emerald-950 text-[8px] md:text-sm">
- <caption className="caption-top text-xs font-semibold">
- Top completes in the past {freq_label}.
- </caption>
- <thead>
- <tr className="
+ border border-zinc-100"
+ >
+ <td className="font-medium">{dataItem.rank}</td>
+ <td className="font-semibold">
+ {formatCentsToUSD(dataItem.value)}
+ </td>
+ <td className="font-light">
+ {truncate(dataItem.bpuid, 6, "*****").toUpperCase()}
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+
+ <table
+ className="border-collapse border border-gray-400
+ text-emerald-950 text-[8px] md:text-sm"
+ >
+ <caption className="caption-top text-xs font-semibold">
+ Top completes in the past {freq_label}.
+ </caption>
+ <thead>
+ <tr
+ className="
font-mono font-semibold text-center
- border border-zinc-150 rounded">
- <th>Rank</th>
- <th>Completes</th>
- <th>User</th>
- </tr>
- </thead>
- <tbody className="font-mono">
-
- {completes?.rows?.map((dataItem: LeaderboardRow, index: number) => (
- <tr key={dataItem.bpuid} className="
+ border border-zinc-150 rounded"
+ >
+ <th>Rank</th>
+ <th>Completes</th>
+ <th>User</th>
+ </tr>
+ </thead>
+ <tbody className="font-mono">
+ {completes?.rows?.map((dataItem: LeaderboardRow, index: number) => (
+ <tr
+ key={dataItem.bpuid}
+ className="
text-center
- border border-zinc-100">
- <td className="font-medium">
- {dataItem.rank ?? showSmartRank(dataItem, index, completes?.rows)}
- </td>
- <td className="font-semibold">
- {dataItem.value}
- </td>
- <td className="font-light">
- {truncate(dataItem.bpuid, 6, "*****").toUpperCase()}
- </td>
- </tr>
- ))}
- </tbody>
- </table>
- </div>
+ border border-zinc-100"
+ >
+ <td className="font-medium">
+ {dataItem.rank ??
+ showSmartRank(dataItem, index, completes?.rows)}
+ </td>
+ <td className="font-semibold">{dataItem.value}</td>
+ <td className="font-light">
+ {truncate(dataItem.bpuid, 6, "*****").toUpperCase()}
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ );
+};
+
+type RequestState = "idle" | "working" | "failed";
+
+interface LoginFormProps {
+ onSubmitSuccess: () => void;
+}
+
+const LoginForm = function ({ onSubmitSuccess }: LoginFormProps) {
+ const [email, setEmail] = useState("");
+ const [state, setState] = useState<RequestState>("idle");
+
+ // const dispatch = useAppDispatch();
+ const submit = async (event: FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ setState("working");
+
+ try {
+ const response = await fetch("/auth/magic-link/request", {
+ method: "POST",
+ credentials: "include",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ email: email,
+ }),
+ });
+
+ if (!response.ok) throw new Error("Account-link request failed");
+ const body = (await response.json()) as { magic_link?: string };
+ console.log(body.magic_link ?? null);
+ onSubmitSuccess();
+ } catch {
+ setState("failed");
+ }
+ };
+
+ return (
+ <>
+ <form className="w-full" onSubmit={submit}>
+ <div className="flex items-center border-b-4 border-blue-700 py-2">
+ <input
+ className="appearance-none bg-transparent border-none w-full text-gray-700 mr-3 py-1 px-2 leading-tight focus:outline-none font-semibold"
+ type="email"
+ autoComplete="email"
+ required
+ value={email}
+ onChange={(event) => setEmail(event.target.value)}
+ placeholder="hello@jamesbillings67.com"
+ aria-label="Email address"
+ />
+
+ <button
+ className="flex-shrink-0 bg-blue-700 hover:bg-blue-800 text-white py-1 px-2 rounded cursor-pointer font-semibold"
+ type="submit"
+ disabled={state === "working"}
+ >
+ {state === "working" ? "Sending…" : "Login / Signup"}
+ </button>
</div>
- );
+ </form>
+
+ {state === "failed" && <p>Unable to send the link. Please try again.</p>}
+ </>
+ );
};
+const LoginSent = function () {
+ return (
+ <div className="my-1">
+ <h2
+ className="
+ bg-emerald-400 rounded py-2
+ text-white text-l font-semibold text-center"
+ >
+ Please check your email.
+ </h2>
+ <p className="text-slate-800 text-xs font-semibold text-center my-1 py-2">
+ If you don't recieve anything, please check your spam folder, or try
+ again shortly.
+ </p>
+ </div>
+ );
+};
+const Login = () => {
+ const [submitted, setSubmitted] = useState(false);
+
+ return (
+ <>
+ {submitted ? (
+ <LoginSent />
+ ) : (
+ <LoginForm onSubmitSuccess={() => setSubmitted(true)} />
+ )}
+ </>
+ );
+};
// Preview Component
const Preview = () => {
- /**
- *
- * @returns {JSX.Element}
- */
-
- const users = useAppSelector(state => activeUsers(state))
- const users_f: string = users?.toLocaleString() ?? " – "
-
- const surveys = useAppSelector(state => activeSurveys(state))
- const surveys_f: string = surveys?.toLocaleString() ?? " – "
-
- const survey_max_cpi = useAppSelector(state => maxPayout(state))
- const formatter = new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency: 'USD',
- });
- const survey_max_cpi_f: string = formatter.format((survey_max_cpi ?? 0) / 100)
-
- return (
- <div className="max-h-[calc(100vh-10rem)] overflow-y-auto">
-
- <div className="bg-zinc-100 rounded py-2 m-0">
- <p className="text-center text-sm italic text-zinc-600">
- {users_f} people are actively attempting {surveys_f} available surveys right now.
- </p>
- </div>
-
- <Leaderboards />
-
- <div className="bg-zinc-100 rounded py-2 px-6 m-0 text-xs text-center">
- <p className="py-1">
- Get paid to take surveys. Our algorithm attempts to pair you with the
- highest paying survey available at the moment (right now, the highest
- paying survey is {survey_max_cpi_f}) that you are eligible for,
- each attempt is a valid HIT. Try as many as you can, our system will
- self regulate you: we want to ensure you have a high chance of being
- paired with a survey based on what surveys are available, as their
- availability constantly changes.</p>
- <p className="py-1">
- Each HIT is paid when you attempt to take a survey and if you complete
- the survey, you will be awarded a bonus equal to that in which the
- survey pays out.</p>
- </div>
+ /**
+ *
+ * @returns {JSX.Element}
+ */
+
+ const users = useAppSelector((state) => activeUsers(state));
+ const users_f: string = users?.toLocaleString() ?? " – ";
+
+ const surveys = useAppSelector((state) => activeSurveys(state));
+ const surveys_f: string = surveys?.toLocaleString() ?? " – ";
+
+ const survey_max_cpi = useAppSelector((state) => maxPayout(state));
+ const formatter = new Intl.NumberFormat("en-US", {
+ style: "currency",
+ currency: "USD",
+ });
+ const survey_max_cpi_f: string = formatter.format(
+ (survey_max_cpi ?? 0) / 100,
+ );
+
+ return (
+ <>
+ <Login />
+
+ <div className="max-h-[calc(100vh-10rem)] overflow-y-auto">
+ <div className="bg-zinc-100 rounded py-2 m-0">
+ <p className="text-center text-sm italic text-zinc-600">
+ {users_f} people are actively attempting {surveys_f} available
+ surveys right now.
+ </p>
</div>
- );
+
+ <Leaderboards />
+
+ <div className="bg-zinc-100 rounded py-2 px-6 m-0 text-xs text-center">
+ <p className="py-1">
+ Get paid to take surveys. Our algorithm attempts to pair you with
+ the highest paying survey available at the moment (right now, the
+ highest paying survey is {survey_max_cpi_f}) that you are eligible
+ for. Try as many as you can, our system will self regulate you: we
+ want to ensure you have a high chance of being paired with a survey
+ based on what surveys are available, as their availability
+ constantly changes.
+ </p>
+ </div>
+ </div>
+ </>
+ );
};
-export default Preview; \ No newline at end of file
+export default Preview;
diff --git a/jb-ui/src/pages/Result.tsx b/jb-ui/src/pages/Result.tsx
index 47af248..6385bc7 100644
--- a/jb-ui/src/pages/Result.tsx
+++ b/jb-ui/src/pages/Result.tsx
@@ -10,114 +10,116 @@ import { useEffect } from "react";
// }
export const Complete = () => {
- const ts = useAppSelector(state => state.app.taskStatus)
-
- return (
- <>
- <h2 className="text-lg">Survey Completed</h2>
- <p className="text-emerald-700 text-lg font-bold">Congratulations! You completed the Survey.</p>
- <p className="text-emerald-700 text-2xl font-bold">{ts?.user_payout_string}</p>
- <p className="text-slate-300">You may close this tab and return to submit the HIT</p>
- </>
- )
-}
+ const ts = useAppSelector((state) => state.app.taskStatus);
+
+ return (
+ <>
+ <h2 className="text-lg">Survey Completed</h2>
+ <p className="text-emerald-700 text-lg font-bold">
+ Congratulations! You completed the Survey.
+ </p>
+ <p className="text-emerald-700 text-2xl font-bold">
+ {ts?.user_payout_string}
+ </p>
+ <p className="text-slate-300">You may close this tab</p>
+ </>
+ );
+};
export const Enter = () => {
- return (
- <>
- <h2 className="text-lg">Entered</h2>
- <p className="text-slate-800 text-lg font-bold">You're currently in the Survey</p>
- <p className="text-slate-300">You may close this tab and return to submit the HIT</p>
- </>
- )
-}
+ return (
+ <>
+ <h2 className="text-lg">Entered</h2>
+ <p className="text-slate-800 text-lg font-bold">
+ You're currently in the Survey
+ </p>
+ <p className="text-slate-300">You may close this tab</p>
+ </>
+ );
+};
export const InComplete = () => {
- const ts = useAppSelector(state => state.app.taskStatus)
- if (!ts) { return null; }
-
- return (
- <>
- <h2 className="text-lg">HIT Complete</h2>
- <p className="text-rose-800 text-lg font-bold">Survey terminated the attempt.</p>
- <p className="text-slate-300">You may close this tab and return to submit the HIT</p>
- </>
-
- )
-}
+ const ts = useAppSelector((state) => state.app.taskStatus);
+ if (!ts) {
+ return null;
+ }
+
+ return (
+ <>
+ <h2 className="text-lg">Attempt Complete</h2>
+ <p className="text-rose-800 text-lg font-bold">
+ Survey terminated the attempt.
+ </p>
+ <p className="text-slate-300">You may close this tab</p>
+ </>
+ );
+};
export const Unknown = () => {
-
- return (
- <>
- <h2 className="text-lg">Task Issue</h2>
- <p className="text-rose-800 text-lg font-bold">You're not currently eligible for any Surveys</p>
- <p className="text-slate-300">You may close this tab and return to submit the HIT</p>
- </>
- )
-}
+ return (
+ <>
+ <h2 className="text-lg">Task Issue</h2>
+ <p className="text-rose-800 text-lg font-bold">
+ You're not currently eligible for any Surveys
+ </p>
+ <p className="text-slate-300">You may close this tab</p>
+ </>
+ );
+};
export const Loading = () => {
-
- return (
- <p className="text-2xl font-semibold">Loading...</p>
- )
-}
-
+ return <p className="text-2xl font-semibold">Loading...</p>;
+};
const Result = () => {
-
- const ts = useAppSelector(state => state.app.taskStatus)
-
- const confettiCannons = () => {
- const end = Date.now() + 3 * 1000
- const colors = ["#84cc16", "#1e3a8a", "#ec4899"]
- const frame = () => {
- if (Date.now() > end) return
- confetti({
- particleCount: 3,
- angle: 60,
- spread: 55,
- startVelocity: 80,
- gravity: 0.7,
- origin: { x: 0, y: 0.8 },
- colors: colors,
- })
- confetti({
- particleCount: 3,
- angle: 120,
- spread: 55,
- startVelocity: 80,
- gravity: 0.7,
- origin: { x: 1, y: 0.8 },
- colors: colors,
- })
- requestAnimationFrame(frame)
- }
- frame()
+ const ts = useAppSelector((state) => state.app.taskStatus);
+
+ const confettiCannons = () => {
+ const end = Date.now() + 3 * 1000;
+ const colors = ["#84cc16", "#1e3a8a", "#ec4899"];
+ const frame = () => {
+ if (Date.now() > end) return;
+ confetti({
+ particleCount: 3,
+ angle: 60,
+ spread: 55,
+ startVelocity: 80,
+ gravity: 0.7,
+ origin: { x: 0, y: 0.8 },
+ colors: colors,
+ });
+ confetti({
+ particleCount: 3,
+ angle: 120,
+ spread: 55,
+ startVelocity: 80,
+ gravity: 0.7,
+ origin: { x: 1, y: 0.8 },
+ colors: colors,
+ });
+ requestAnimationFrame(frame);
+ };
+ frame();
+ };
+
+ useEffect(() => {
+ if (ts?.status === 3) {
+ confettiCannons();
}
-
- useEffect(() => {
- if (ts?.status === 3) {
- confettiCannons()
- }
- }, [ts])
-
-
- switch (ts?.status) {
- case 0: // UNKNOWN
- return <Unknown />;
- case 1: // ENTER
- return <Enter />;
- case 2: // INCOMPLETE
- return <InComplete />;
- case 3: // COMPLETE
- return <Complete />;
- default:
- return <Loading />;
- }
-
+ }, [ts]);
+
+ switch (ts?.status) {
+ case 0: // UNKNOWN
+ return <Unknown />;
+ case 1: // ENTER
+ return <Enter />;
+ case 2: // INCOMPLETE
+ return <InComplete />;
+ case 3: // COMPLETE
+ return <Complete />;
+ default:
+ return <Loading />;
+ }
};
-
-export default Result; \ No newline at end of file
+export default Result;
diff --git a/jb-ui/src/pages/Transfer.tsx b/jb-ui/src/pages/Transfer.tsx
new file mode 100644
index 0000000..8079da2
--- /dev/null
+++ b/jb-ui/src/pages/Transfer.tsx
@@ -0,0 +1,162 @@
+import { type FormEvent, useState } from "react";
+import { useAppSelector } from "@/hooks";
+import { useGetMeQuery } from "@/models/authAPI";
+import { Button } from "@/components/ui/button";
+import max_lulu from "./max-and-lulu.jpg";
+
+// const handleInputChange = (
+// event: React.KeyboardEvent<HTMLInputElement>,
+// ) => {};
+
+// const handleKeyPress = (event: KeyboardEvent<HTMLInputElement>) => {};
+// const handleSubmit = (e) => {
+// e.preventDefault();
+// console.log("Form submitted successfully!");
+// };
+
+const TransferComplete = function () {
+ return (
+ <div className="px-6 my-6">
+ <h2
+ className="
+ bg-emerald-400 rounded py-2
+ text-white text-2xl font-semibold text-center"
+ >
+ Please check your email.
+ </h2>
+ <p className="text-slate-600 text-l font-semibold text-center py-5 px-6">
+ If you don't recieve anything, please check your spam folder, or try
+ again shortly.
+ </p>
+ <p className="bg-slate-200 text-xs font-semibold text-center p-3 my-3">
+ We will be assisting account transfers throughout the rest of the month.
+ If you have any further questions or concerns, please email us directly
+ with your desired account email and the AMT ID to associate with your
+ worker history.
+ </p>
+ <img src={max_lulu} alt="Max and Lulu" className="object-contain" />
+ </div>
+ );
+};
+
+type RequestState = "idle" | "working" | "sent" | "failed";
+
+interface TransferSubmitProps {
+ onSubmitSuccess: () => void;
+}
+
+const TransferSubmit = function ({ onSubmitSuccess }: TransferSubmitProps) {
+ const [email, setEmail] = useState("");
+ const [state, setState] = useState<RequestState>("idle");
+ const { data: user } = useGetMeQuery();
+
+ const submit = async (event: FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ setState("working");
+
+ try {
+ const response = await fetch("/auth/link-amt/request", {
+ method: "POST",
+ credentials: "include",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ email: email,
+ amt_worker_id: user?.product_user_id,
+ }),
+ });
+
+ if (!response.ok) throw new Error("Account-link request failed");
+
+ const body = (await response.json()) as { magic_link?: string };
+ console.log(body.magic_link ?? null);
+ onSubmitSuccess();
+ } catch {
+ setState("failed");
+ }
+ };
+
+ return (
+ <div className="px-6 my-6">
+ <h2
+ className="
+ bg-red-700 rounded py-2
+ text-white text-2xl font-semibold text-center"
+ >
+ Transfer Required
+ </h2>
+ <h4
+ className="
+ mt-2
+ bg-slate-500 rounded p-2
+ text-white text-sm font-semibold text-center"
+ >
+ James Billings is no longer available on Amazon Mechanical Turk. Our
+ dedicated platform will enable you to do the same work as always, paid
+ directly to you.
+ <br />
+ Enter your email below to transfer your account history.
+ <br />
+ This will allow you to keep your full account history and wallet
+ balance.
+ </h4>
+
+ <form onSubmit={submit}>
+ <input
+ className="w-full rounded-md border-3 border-slate-700 px-3 py-2 font-semibold my-5"
+ type="email"
+ autoComplete="email"
+ required
+ value={email}
+ onChange={(event) => setEmail(event.target.value)}
+ placeholder="you@example.com"
+ />
+ <Button
+ className="w-1/2 font-semibold bg-slate-600 cursor-pointer hover:bg-blue-950"
+ type="submit"
+ disabled={state === "working"}
+ >
+ {state === "working" ? "Sending…" : "Send link"}
+ </Button>
+ </form>
+
+ {state === "sent" && (
+ <h4
+ className="
+ mt-2
+ bg-slate-500 rounded py-2
+ text-white text-l font-semibold text-center"
+ >
+ Check your email to finish linking your account.
+ </h4>
+ )}
+
+ {state === "failed" && <p>Unable to send the link. Please try again.</p>}
+ </div>
+ );
+};
+
+const Transfer = function () {
+ const bpuid = useAppSelector((state) => state.app.bpuid);
+ const [submitted, setSubmitted] = useState(false);
+
+ if (!bpuid) {
+ return (
+ <p className="text-center text-2xl py-3 text-red-800 font-semibold">
+ No Worker ID found. Please access this page through the Amazon
+ Mechanical Turk platform.
+ </p>
+ );
+ }
+
+ return (
+ <>
+ {submitted ? (
+ <TransferComplete />
+ ) : (
+ <TransferSubmit onSubmitSuccess={() => setSubmitted(true)} />
+ )}
+ </>
+ );
+};
+
+export default Transfer;
diff --git a/jb-ui/src/pages/Work.tsx b/jb-ui/src/pages/Work.tsx
index c54732f..6d0b1c1 100644
--- a/jb-ui/src/pages/Work.tsx
+++ b/jb-ui/src/pages/Work.tsx
@@ -1,765 +1,818 @@
+import { useGetMeQuery } from "@/models/authAPI";
+import { Link } from "react-router-dom";
import {
- BucketTask,
- OfferwallApi,
- OfferwallReason,
- ReportApi, ReportTask, ReportValue, StatusApi,
- TasksStatusResponse, TaskStatusResponse, TopNPlusBlockOfferWall
+ BucketTask,
+ OfferwallApi,
+ OfferwallReason,
+ ReportApi,
+ ReportTask,
+ ReportValue,
+ StatusApi,
+ TasksStatusResponse,
+ TaskStatusResponse,
+ TopNPlusBlockOfferWall,
} from "@/api_fsb";
+import Preview from "@/pages/Preview";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
- Field,
- FieldDescription,
- FieldGroup,
- FieldLabel,
- FieldLegend,
- FieldSet,
+ Field,
+ FieldDescription,
+ FieldGroup,
+ FieldLabel,
+ FieldLegend,
+ FieldSet,
} from "@/components/ui/field";
import { useAppDispatch, useAppSelector } from "@/hooks";
import { bpid, formatCentsToUSD, formatSource, truncate } from "@/lib/utils";
import {
- getAvailabilityCount, getLOIText,
- isLowBalance,
- selectBucket,
- setAttemptedLiveEligibleCount,
- setAvailabilityCount,
- setCurrentBuckets,
- setEnteredTimestamp, setLOI,
- setOfferwallReasons,
- setTaskStatus
+ getAvailabilityCount,
+ getLOIText,
+ isLowBalance,
+ selectBucket,
+ setAttemptedLiveEligibleCount,
+ setAvailabilityCount,
+ setCurrentBuckets,
+ setEnteredTimestamp,
+ setLOI,
+ setOfferwallReasons,
+ setTaskStatus,
} from "@/models/appSlice";
import {
- createColumnHelper, flexRender, getCoreRowModel,
- useReactTable
+ createColumnHelper,
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
} from "@tanstack/react-table";
import { XIcon } from "lucide-react";
import moment from "moment/moment";
-import { useEffect, useRef, useState } from "react";
-import Markdown from 'react-markdown';
+import { useEffect, useState } from "react";
+import Markdown from "react-markdown";
const Report = ({ onClose }: { onClose: () => void }) => {
- const [showComplete, setShowComplete] = useState(false);
- const [selectedValues, setSelectedValues] = useState<ReportValue[]>([]);
-
- const bpuid = useAppSelector(state => state.app.bpuid)
- const ts = useAppSelector(state => state.app.taskStatus)
-
- const handleCheckboxChange = (value: ReportValue, checked: boolean) => {
- setSelectedValues(prev =>
- checked
- ? [...prev, value]
- : prev.filter(v => v !== value)
- );
+ const [, setShowComplete] = useState(false);
+ const [selectedValues, setSelectedValues] = useState<ReportValue[]>([]);
+ const { data: user } = useGetMeQuery();
+ const ts = useAppSelector((state) => state.app.taskStatus);
+
+ const handleCheckboxChange = (value: ReportValue, checked: boolean) => {
+ setSelectedValues((prev) =>
+ checked ? [...prev, value] : prev.filter((v) => v !== value),
+ );
+ };
+
+ const clicked_submit = () => {
+ if (!user?.product_user_id) return;
+ // ReportValue.NUMBER_0
+ console.log("selectedValues:", selectedValues);
+
+ const rt: ReportTask = {
+ bpuid: user.product_user_id,
+ reasons: selectedValues,
+ notes: "",
};
- const clicked_submit = () => {
- if (!bpuid) return;
- // ReportValue.NUMBER_0
- console.log("selectedValues:", selectedValues);
-
- const rt: ReportTask = {
- 'bpuid': bpuid,
- 'reasons': selectedValues,
- 'notes': ""
- };
-
- new ReportApi().reportTaskProductIdReportPost(
- bpid, // productId
- rt, // reportTask
- ).then(res => {
- console.log("Response:", res); // Check what's actually here
-
- if (res.status === 400) {
- // Handle error here instead
- } else {
- setShowComplete(true);
- }
- })
- }
-
- const reportReasons = [
- { id: 'TECHNICAL_ERROR', label: 'Technical Error', value: ReportValue.NUMBER_1 },
- { id: 'NO_REDIRECT', label: 'No Redirect', value: ReportValue.NUMBER_2 },
- { id: 'PRIVACY_INVASION', label: 'Privacy Invasion', value: ReportValue.NUMBER_3 },
- { id: 'UNCOMFORTABLE_TOPICS', label: 'Uncomfortable Topics', value: ReportValue.NUMBER_4 },
- { id: 'ASKED_FOR_NOT_ALLOWED_ACTION', label: 'Asked for Not Allowed Action', value: ReportValue.NUMBER_5 },
- { id: 'BAD_ON_MOBILE', label: 'Bad on Mobile', value: ReportValue.NUMBER_6 },
- { id: 'DIDNT_LIKE', label: "Didn't Like", value: ReportValue.NUMBER_7 },
- ];
-
- if (!ts?.finished) {
- return <p>Please finish a Task to report its status.</p>
- }
-
- if (showComplete) {
- return <SubimtAMT />
- }
-
- return (
- <div className="border-2 border-rose-200 rounded">
- <div className="flex justify-center">
- <FieldSet className="mt-2">
- <FieldLegend variant="label" className="my-0 text-rose-950">
- Please select all reasons why you are reporting this Task:
- </FieldLegend>
- <FieldDescription className="my-0 text-rose-950">
- You must provide at least one reason to report a Task.
- </FieldDescription>
- <FieldGroup className="gap-2 my-0 py-0">
-
- {reportReasons.map((reason) => (
- <Field key={reason.id} orientation="horizontal" className="
- hover:cursor-pointer">
- <Checkbox
- id={reason.id}
- name={reason.id}
- onCheckedChange={(checked) =>
- handleCheckboxChange(reason.value, checked as boolean)
- }
- />
- <FieldLabel
- htmlFor={reason.id}
- className="font-medium text-rose-950
+ new ReportApi()
+ .reportTaskProductIdReportPost(
+ bpid, // productId
+ rt, // reportTask
+ )
+ .then((res) => {
+ console.log("Response:", res); // Check what's actually here
+
+ if (res.status === 400) {
+ // Handle error here instead
+ } else {
+ setShowComplete(true);
+ }
+ });
+ };
+
+ const reportReasons = [
+ {
+ id: "TECHNICAL_ERROR",
+ label: "Technical Error",
+ value: ReportValue.NUMBER_1,
+ },
+ { id: "NO_REDIRECT", label: "No Redirect", value: ReportValue.NUMBER_2 },
+ {
+ id: "PRIVACY_INVASION",
+ label: "Privacy Invasion",
+ value: ReportValue.NUMBER_3,
+ },
+ {
+ id: "UNCOMFORTABLE_TOPICS",
+ label: "Uncomfortable Topics",
+ value: ReportValue.NUMBER_4,
+ },
+ {
+ id: "ASKED_FOR_NOT_ALLOWED_ACTION",
+ label: "Asked for Not Allowed Action",
+ value: ReportValue.NUMBER_5,
+ },
+ {
+ id: "BAD_ON_MOBILE",
+ label: "Bad on Mobile",
+ value: ReportValue.NUMBER_6,
+ },
+ { id: "DIDNT_LIKE", label: "Didn't Like", value: ReportValue.NUMBER_7 },
+ ];
+
+ if (!ts?.finished) {
+ return <p>Please finish a Task to report its status.</p>;
+ }
+
+ // TODO! What do we do here, redirect back to / with a thank you + wallet refresh?
+ // if (showComplete) {
+ // return <SubimtAMT />;
+ // }
+
+ return (
+ <div className="border-2 border-rose-200 rounded">
+ <div className="flex justify-center">
+ <FieldSet className="mt-2">
+ <FieldLegend variant="label" className="my-0 text-rose-950">
+ Please select all reasons why you are reporting this Task:
+ </FieldLegend>
+ <FieldDescription className="my-0 text-rose-950">
+ You must provide at least one reason to report a Task.
+ </FieldDescription>
+ <FieldGroup className="gap-2 my-0 py-0">
+ {reportReasons.map((reason) => (
+ <Field
+ key={reason.id}
+ orientation="horizontal"
+ className="
+ hover:cursor-pointer"
+ >
+ <Checkbox
+ id={reason.id}
+ name={reason.id}
+ onCheckedChange={(checked) =>
+ handleCheckboxChange(reason.value, checked as boolean)
+ }
+ />
+ <FieldLabel
+ htmlFor={reason.id}
+ className="font-medium text-rose-950
hover:cursor-pointer hover:font-semibold"
- >
- {reason.label}
- </FieldLabel>
- </Field>
- ))}
-
- </FieldGroup>
- </FieldSet>
- </div>
- <div className="flex justify-center my-2 space-x-5">
- <Button variant="outline" size="icon" aria-label="Submit"
- className="
+ >
+ {reason.label}
+ </FieldLabel>
+ </Field>
+ ))}
+ </FieldGroup>
+ </FieldSet>
+ </div>
+ <div className="flex justify-center my-2 space-x-5">
+ <Button
+ variant="outline"
+ size="icon"
+ aria-label="Submit"
+ className="
border-2 rounded border-zinc-800 text-zinc-800
hover:cursor-pointer hover:bg-zinc-800 hover:text-zinc-50"
- onClick={onClose}>
- <XIcon />
- </Button>
- <Button variant="outline"
- className="
+ onClick={onClose}
+ >
+ <XIcon />
+ </Button>
+ <Button
+ variant="outline"
+ className="
border-2 rounded border-rose-400 text-rose-950
hover:cursor-pointer hover:bg-rose-400 hover:text-rose-50"
- onClick={clicked_submit}>Submit and Complete HIT</Button>
- </div>
- </div>
- )
-}
+ onClick={clicked_submit}
+ >
+ Submit and Complete Attempt
+ </Button>
+ </div>
+ </div>
+ );
+};
-const SubimtAMT = () => {
- const bpuid = useAppSelector(state => state.app.bpuid)
- const assignment_id = useAppSelector(state => state.app.assignment_id)
- const ts = useAppSelector(state => state.app.taskStatus)
- const turkSubmitTo = useAppSelector(state => state.app.turkSubmitTo)
+const SurveyMonitor = () => {
+ const dispatch = useAppDispatch();
- const formRef = useRef<HTMLFormElement>(null);
+ const [isPolling, setIsPolling] = useState(true);
+ // const [timeAgo, setTimeAgo] = useState("");
- useEffect(() => {
- if (!ts) return;
- if (!bpuid) return;
- if (!assignment_id) return;
- if (!turkSubmitTo) return;
+ const [, setShowComplete] = useState(false);
+ const [showReport, setShowReport] = useState(false);
- if (formRef.current) {
- formRef.current.submit();
- }
- }, [ts?.tsid, bpuid, assignment_id, turkSubmitTo]);
+ const { data: user } = useGetMeQuery();
+ const entered = useAppSelector((state) => state.app.currentBucketEntered);
+ const isLow = useAppSelector((state) => isLowBalance(state));
- return (
- <>
- <form
- ref={formRef}
- action={`${turkSubmitTo}/mturk/externalSubmit`}
- method="POST"
- style={{ display: 'none' }}>
- <input type="hidden" name="assignmentId" value={assignment_id} />
- <input type="hidden" name="tsid" value={ts?.tsid} />
- <input type="hidden" name="amt_assignment_id" value={assignment_id} />
- <input type="hidden" name="amt_worker_id" value={bpuid} />
- <button type="submit">Submit HIT</button>
- </form>
- </>
- )
-}
+ const ts = useAppSelector((state) => state.app.taskStatus);
+ const isBaddie =
+ ts?.status_code_1 === "SESSION_START_FAIL" ||
+ ts?.status_code_1 === "SESSION_START_QUALITY_FAIL" ||
+ ts?.status_code_1 === "SESSION_CONTINUE_QUALITY_FAIL";
+ // useEffect(() => {
+ // if (!ts) return;
-const SurveyMonitor = () => {
- const dispatch = useAppDispatch()
-
- const [isPolling, setIsPolling] = useState(true);
- // const [timeAgo, setTimeAgo] = useState("");
-
- const [showComplete, setShowComplete] = useState(false);
- const [showReport, setShowReport] = useState(false);
-
- const bpuid = useAppSelector(state => state.app.bpuid)
- const entered = useAppSelector(state => state.app.currentBucketEntered)
- const isLow = useAppSelector(state => isLowBalance(state))
-
- const ts = useAppSelector(state => state.app.taskStatus)
- const isBaddie = ts?.status_code_1 === "SESSION_START_FAIL" || ts?.status_code_1 === "SESSION_START_QUALITY_FAIL" || ts?.status_code_1 === "SESSION_CONTINUE_QUALITY_FAIL";
-
- // useEffect(() => {
- // if (!ts) return;
-
- // const updateTimeAgo = () => {
- // const time_ago = moment(ts.started).fromNow();
- // setTimeAgo(time_ago);
- // };
-
- // // Update immediately
- // updateTimeAgo();
-
- // // Then update every minute
- // const intervalId = setInterval(updateTimeAgo, 60 * 1000);
-
- // return () => clearInterval(intervalId);
- // }, [ts]);
-
- useEffect(() => {
- if (!bpuid) return;
- if (!entered) return;
- if (!isPolling) return;
-
- const pollApi = async () => {
- new StatusApi().listTaskStatusesProductIdStatusGet(
- bpid, // productId
- bpuid, // Worker ID
- entered, // startedAfter
- moment.utc().unix() // startedBefore
- ).then(res => {
- const d = res.data as TasksStatusResponse;
-
- if (!d.tasks_status || d.tasks_status.length === 0) {
- // Likely still in a GRS survey
- return;
- }
-
- // if (d_len >= 2) Sentry.captureMessage("Results returned back multiple")
- const ts = d.tasks_status![0] as TaskStatusResponse;
- dispatch(setTaskStatus(ts))
-
- if (ts.status == 2 || ts.status == 3) {
- // INCOMPLETE + COMPLETE
- setIsPolling(false);
- }
- });
-
- // If there is already a TaskStatus, update the time ago
- // if (ts) {
- // const time_ago = moment(ts.started).fromNow();
- // setTimeAgo(time_ago);
- // }
- };
-
- // Call immediately on mount, then set up interval
- pollApi();
- const intervalId = setInterval(pollApi, 4 * 1000);
-
- // Cleanup: stop interval when component unmounts or isPolling changes
- return () => clearInterval(intervalId);
- }, [isPolling, entered]);
-
- if (!ts) {
- return (
- <p>Loading</p>
- )
- }
-
- // This is if they are actively in a survey or we can't determine the
- // status yet. We want to show the timer and keep them on this page to
- // monitor for completion. This gets shown no matter what regardless of
- // balance.
- //
- // 0 - UNKNOWN, 1 - ENTER
- if (ts.status === 0 || ts.status === 1) {
- return (
- <>
- <div>
- <h2 className="
- bg-blue-500 rounded py-2
- text-white text-2xl font-semibold text-center">
- In Progress
- </h2>
- <p className="
- py-4
- text-zinc-500 text-2xl font-semibold text-center">
- We're actively monitoring your Task status.
- </p>
- </div>
- </>
+ // const updateTimeAgo = () => {
+ // const time_ago = moment(ts.started).fromNow();
+ // setTimeAgo(time_ago);
+ // };
+
+ // // Update immediately
+ // updateTimeAgo();
+
+ // // Then update every minute
+ // const intervalId = setInterval(updateTimeAgo, 60 * 1000);
+
+ // return () => clearInterval(intervalId);
+ // }, [ts]);
+
+ useEffect(() => {
+ if (!user?.product_user_id) return;
+ if (!entered) return;
+ if (!isPolling) return;
+
+ const pollApi = async () => {
+ new StatusApi()
+ .listTaskStatusesProductIdStatusGet(
+ bpid, // productId
+ user.product_user_id, // Worker ID
+ entered, // startedAfter
+ moment.utc().unix(), // startedBefore
)
- }
+ .then((res) => {
+ const d = res.data as TasksStatusResponse;
+
+ if (!d.tasks_status || d.tasks_status.length === 0) {
+ // Likely still in a GRS survey
+ return;
+ }
+
+ // if (d_len >= 2) Sentry.captureMessage("Results returned back multiple")
+ const ts = d.tasks_status![0] as TaskStatusResponse;
+ dispatch(setTaskStatus(ts));
+
+ if (ts.status == 2 || ts.status == 3) {
+ // INCOMPLETE + COMPLETE
+ setIsPolling(false);
+ }
+ });
- // This is if they have finished a survey complete and it resulted in a
- // COMPLETE or a INCOMPLETE (doesn't matter). They can now submit the HIT.
- //
- // 2 - INCOMPLETE, 3 - COMPLETE
+ // If there is already a TaskStatus, update the time ago
+ // if (ts) {
+ // const time_ago = moment(ts.started).fromNow();
+ // setTimeAgo(time_ago);
+ // }
+ };
+
+ // Call immediately on mount, then set up interval
+ pollApi();
+ const intervalId = setInterval(pollApi, 4 * 1000);
+
+ // Cleanup: stop interval when component unmounts or isPolling changes
+ return () => clearInterval(intervalId);
+ }, [isPolling, entered]);
+
+ if (!ts) {
+ return <p>Loading</p>;
+ }
+
+ // This is if they are actively in a survey or we can't determine the
+ // status yet. We want to show the timer and keep them on this page to
+ // monitor for completion. This gets shown no matter what regardless of
+ // balance.
+ //
+ // 0 - UNKNOWN, 1 - ENTER
+ if (ts.status === 0 || ts.status === 1) {
return (
- <>
- <div>
- <h2 className="
+ <>
+ <div>
+ <h2
+ className="
bg-blue-500 rounded py-2
- text-white text-2xl font-semibold text-center">
- {ts.status === 3 ? "Survey Complete!" : "Survey Terminated."}
- </h2>
-
- {((ts.status === 3 || !isLow) && !isBaddie) && (
- <p className="
+ text-white text-2xl font-semibold text-center"
+ >
+ In Progress
+ </h2>
+ <p
+ className="
+ py-4
+ text-zinc-500 text-2xl font-semibold text-center"
+ >
+ We're actively monitoring your Task status.
+ </p>
+ </div>
+ </>
+ );
+ }
+
+ // This is if they have finished a survey complete and it resulted in a
+ // COMPLETE or a INCOMPLETE (doesn't matter). They can now submit the Attempt.
+ //
+ // 2 - INCOMPLETE, 3 - COMPLETE
+ return (
+ <>
+ <div>
+ <h2
+ className="
+ bg-blue-500 rounded py-2
+ text-white text-2xl font-semibold text-center"
+ >
+ {ts.status === 3 ? "Survey Complete!" : "Survey Terminated."}
+ </h2>
+
+ {(ts.status === 3 || !isLow) && !isBaddie && (
+ <p
+ className="
py-2
- text-zinc-500 text-md font-medium text-center">
- You may now submit the HIT.
- </p>
- )}
- </div>
-
- {(isBaddie) ? (
- <>
- <div className="
+ text-zinc-500 text-md font-medium text-center"
+ >
+ You may now submit the attempt.
+ </p>
+ )}
+ </div>
+
+ {isBaddie ? (
+ <>
+ <div
+ className="
border-2 border-rose-500 rounded py-2
- bg-rose-400 text-rose-700">
- <h2 className="text-center text-xl font-bold text-white">
- Quality Check Failed.
- </h2>
- <p className="px-4 py-2 text-center text-sm font-medium text-white">
- Unfortunately, it looks like you did not pass the quality check for this survey.
- </p>
-
- <p className="
+ bg-rose-400 text-rose-700"
+ >
+ <h2 className="text-center text-xl font-bold text-white">
+ Quality Check Failed.
+ </h2>
+ <p className="px-4 py-2 text-center text-sm font-medium text-white">
+ Unfortunately, it looks like you did not pass the quality check
+ for this survey.
+ </p>
+
+ <p
+ className="
pt-0 pb-4
- text-red-950 text-sm font-semibold text-center">
- Please return the HIT to avoid having your assignment rejected.
- </p>
- </div>
- </>
-
- ) : (
- <>
- {(ts.status === 3 || !isLow) ? (
- <>
- <div className="flex justify-center my-4 space-x-5">
-
- <button type="button" className="
+ text-red-950 text-sm font-semibold text-center"
+ >
+ <Link to="/" reloadDocument>
+ Click to Refresh and Try Again
+ </Link>
+ </p>
+ </div>
+ </>
+ ) : (
+ <>
+ {ts.status === 3 || !isLow ? (
+ <>
+ <div className="flex justify-center my-4 space-x-5">
+ <button
+ type="button"
+ className="
border-4 rounded border-emerald-400 py-1 px-3
text-xl font-bold text-emerald-950
hover:cursor-pointer hover:bg-emerald-400 hover:text-emerald-50"
- onClick={() => setShowComplete(true)}
- >Submit HIT</button>
-
- <button type="button" className="
+ onClick={() => setShowComplete(true)}
+ >
+ Finish Attempt
+ </button>
+
+ <button
+ type="button"
+ className="
border-4 rounded border-rose-200 py-1 px-3
text-xl font-bold text-rose-200
hover:cursor-pointer hover:border-rose-500 hover:bg-rose-400 hover:text-rose-50"
- onClick={() => setShowReport(!showReport)}
- >Report Survey</button>
- </div>
-
- {showComplete && <SubimtAMT />}
- {showReport && <Report onClose={() => setShowReport(false)} />}
- </>
- ) : (
- <div>
- <p className="
- text-red-600 text-lg font-semibold text-center">
- Your balance is low. You cannot submit the HIT at this time.
- </p>
-
- <p className="
- pt-0 pb-4
- text-red-950 text-sm font-semibold text-center">
- Please return the HIT to avoid having your assignment rejected.
- </p>
- </div>
- )}
- </>
-
- )}
-
-
+ onClick={() => setShowReport(!showReport)}
+ >
+ Report Survey
+ </button>
+ </div>
+ {/* TODO! What do we do here, redirect back to / with wallet */}
+ {/* TODO! refresh? The confetti is on a different page. */}
+ {/* {showComplete && <SubimtAMT />} */}
+ {showReport && <Report onClose={() => setShowReport(false)} />}
+ </>
+ ) : (
+ <div>
+ <p
+ className="
+ text-red-600 text-lg font-semibold text-center"
+ >
+ Your balance is low.
+ </p>
+ </div>
+ )}
</>
- )
-}
-
+ )}
+ </>
+ );
+};
const LOISelect = () => {
- // This is what's responsible for being able to click on the text
- // we set the global LOI times.
-
- const dispatch = useAppDispatch()
- const loi: number = useAppSelector(state => state.app.loi)
- const bucket = useAppSelector(state => selectBucket(state))
-
- const toggle_loi = function () {
- dispatch(setLOI(loi >= 1800 ? 600 : loi + 600))
- }
-
- const time_f = useAppSelector(state => getLOIText(state))
-
- const avg_time_f = ((bucket?.duration.q2 ?? 0) / 60).toLocaleString(
- 'en-US', { minimumFractionDigits: 0, maximumFractionDigits: 1 })
-
- const formatter = new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency: 'USD',
- });
- const avg_pay_f: string = formatter.format((bucket?.payout.q2 ?? 0) / 100)
-
- return (
- <div className="bg-zinc-100 rounded py-2 m-0">
- <p className="text-zinc-700 text-2xl text-center font-bold m-0">
- I have <span
- className="cursor-pointer text-emerald-600 italic hover:text-emerald-700 hover:underline"
- onClick={toggle_loi}>{time_f}</span> minutes
- </p>
- <p
- className="text-center text-xs font-thin m-0 text-zinc-500">
- The average time spent is {avg_time_f} minutes and pays {avg_pay_f}</p>
- </div>
- )
-
+ // This is what's responsible for being able to click on the text
+ // we set the global LOI times.
+
+ const dispatch = useAppDispatch();
+ const loi: number = useAppSelector((state) => state.app.loi);
+ const bucket = useAppSelector((state) => selectBucket(state));
+
+ const toggle_loi = function () {
+ dispatch(setLOI(loi >= 1800 ? 600 : loi + 600));
+ };
+
+ const time_f = useAppSelector((state) => getLOIText(state));
+
+ const avg_time_f = ((bucket?.duration.q2 ?? 0) / 60).toLocaleString("en-US", {
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 1,
+ });
+
+ const formatter = new Intl.NumberFormat("en-US", {
+ style: "currency",
+ currency: "USD",
+ });
+ const avg_pay_f: string = formatter.format((bucket?.payout.q2 ?? 0) / 100);
+
+ return (
+ <div className="bg-zinc-100 rounded py-2 m-0">
+ <p className="text-zinc-700 text-2xl text-center font-bold m-0">
+ I have{" "}
+ <span
+ className="cursor-pointer text-emerald-600 italic hover:text-emerald-700 hover:underline"
+ onClick={toggle_loi}
+ >
+ {time_f}
+ </span>{" "}
+ minutes
+ </p>
+ <p className="text-center text-xs font-thin m-0 text-zinc-500">
+ The average time spent is {avg_time_f} minutes and pays {avg_pay_f}
+ </p>
+ </div>
+ );
};
const SurveyLoading = () => {
- return (
- <div className="
+ return (
+ <div
+ className="
border-8 border-emerald-400 rounded py-0 my-2
text-center text-3xl
- hover:cursor-pointer hover:bg-green-500 hover:text-white">
- <p className="py-2 text-center text-3xl font-semibold">
- Survey Loading…
- </p>
- </div>
- )
-}
-
+ hover:cursor-pointer hover:bg-green-500 hover:text-white"
+ >
+ <p className="py-2 text-center text-3xl font-semibold">Survey Loading…</p>
+ </div>
+ );
+};
const NoSurveys = () => {
- const offerwall_reasons = useAppSelector(state => state.app.offerwall_reasons)
-
- const REASON_DISPLAY: Record<OfferwallReason, { label: string; description: string }> = {
- [OfferwallReason.UserBlocked]: {
- label: "Account Restricted",
- description: "Your account has been restricted.",
- },
- [OfferwallReason.HighReconRate]: {
- label: "High Reconciliation Rate",
- description: "Your account has an unusually high reconciliation rate.",
- },
- [OfferwallReason.UncommonDemographics]: {
- label: "Demographic Mismatch",
- description: "No surveys require your current demographics.",
- },
- [OfferwallReason.UnderMinimumAge]: {
- label: "Age Requirement Not Met",
- description: "You must meet the minimum age requirement to participate.",
- },
- [OfferwallReason.ExhaustedHighValueSupply]: {
- label: "No Premium Offers Available",
- description: "You've attempted all premium surveys.",
- },
- [OfferwallReason.AllEligibleAttempted]: {
- label: "All Offers Attempted",
- description: "You've attempted all available surveys.",
- },
- [OfferwallReason.LowCurrentSupply]: {
- label: "Limited Availability",
- description: "There are currently limited opportunities available.",
- },
- };
+ const offerwall_reasons = useAppSelector(
+ (state) => state.app.offerwall_reasons,
+ );
- function formatReasons(reasons: OfferwallReason[]): { label: string; description: string }[] {
- return reasons.map((r) => REASON_DISPLAY[r]);
- }
-
- return (
- <>
- <div className="
+ const REASON_DISPLAY: Record<
+ OfferwallReason,
+ { label: string; description: string }
+ > = {
+ [OfferwallReason.UserBlocked]: {
+ label: "Account Restricted",
+ description: "Your account has been restricted.",
+ },
+ [OfferwallReason.HighReconRate]: {
+ label: "High Reconciliation Rate",
+ description: "Your account has an unusually high reconciliation rate.",
+ },
+ [OfferwallReason.UncommonDemographics]: {
+ label: "Demographic Mismatch",
+ description: "No surveys require your current demographics.",
+ },
+ [OfferwallReason.UnderMinimumAge]: {
+ label: "Age Requirement Not Met",
+ description: "You must meet the minimum age requirement to participate.",
+ },
+ [OfferwallReason.ExhaustedHighValueSupply]: {
+ label: "No Premium Offers Available",
+ description: "You've attempted all premium surveys.",
+ },
+ [OfferwallReason.AllEligibleAttempted]: {
+ label: "All Offers Attempted",
+ description: "You've attempted all available surveys.",
+ },
+ [OfferwallReason.LowCurrentSupply]: {
+ label: "Limited Availability",
+ description: "There are currently limited opportunities available.",
+ },
+ };
+
+ function formatReasons(
+ reasons: OfferwallReason[],
+ ): { label: string; description: string }[] {
+ return reasons.map((r) => REASON_DISPLAY[r]);
+ }
+
+ return (
+ <>
+ <div
+ className="
border-8 border-emerald-400 rounded py-0 my-2
text-center text-3xl
- hover:cursor-pointer hover:bg-green-500 hover:text-white">
- <p className="py-2 text-center text-3xl font-semibold">
- No Surveys available…
- </p>
- </div>
-
- {formatReasons(offerwall_reasons).map(r => {
- return (
- <div className="
+ hover:cursor-pointer hover:bg-green-500 hover:text-white"
+ >
+ <p className="py-2 text-center text-3xl font-semibold">
+ No Surveys available…
+ </p>
+ </div>
+
+ {formatReasons(offerwall_reasons).map((r) => {
+ return (
+ <div
+ className="
border-6 border-rose-200 rounded py-0 my-2
text-center
- hover:cursor-pointer hover:bg-rose-200 hover:text-rose-950 ">
- <p className="py-2 text-center text-md font-semibold text-rose-600">
- {r.description}
- </p>
- </div>
- )
- })}
- </>
- )
-}
+ hover:cursor-pointer hover:bg-rose-200 hover:text-rose-950 "
+ >
+ <p className="py-2 text-center text-md font-semibold text-rose-600">
+ {r.description}
+ </p>
+ </div>
+ );
+ })}
+ </>
+ );
+};
const BucketDetails = () => {
- const bucket = useAppSelector(state => selectBucket(state))
- if (!bucket) return null;
- const [showDetails, setShowDetails] = useState(false);
-
- const columnHelper = createColumnHelper<BucketTask>()
- const columns = [
- columnHelper.display({
- id: 'index',
- header: '#',
- cell: ({ row }) => row.index + 1,
- size: 25,
- meta: {
- align: 'center'
- }
- }),
- columnHelper.accessor('source', {
- header: () => 'Marketplace',
- cell: (props) => {
- const s = props.getValue()
- return formatSource(s)
- },
- size: 85,
- meta: {
- align: 'left'
- }
- }),
- columnHelper.accessor('id', {
- header: () => 'Survey ID',
- cell: props => {
- return truncate(props.getValue(), 6, "*****").toUpperCase()
- },
- size: 70,
- meta: {
- align: 'left'
- }
- }),
- columnHelper.accessor('payout', {
- header: () => 'Amount',
- cell: (props) => {
- const val = props.renderValue() as number;
- return formatCentsToUSD(val)
- },
- size: 50,
- meta: {
- align: 'center'
- }
- }),
- columnHelper.accessor('loi', {
- header: () => 'Duration',
- cell: (props) => {
- const val = props.renderValue() as number;
- return `${Math.round(val / 60)} min`
- },
- size: 50,
- meta: {
- align: 'center'
- }
- }),
- ]
-
- const table = useReactTable({
- 'data': bucket.contents,
- 'columns': columns,
- getCoreRowModel: getCoreRowModel(),
- });
-
- return (
- <>
- <div className="w-full text-center text-[8px] text-emerald-600
+ const bucket = useAppSelector((state) => selectBucket(state));
+ if (!bucket) return null;
+ const [showDetails, setShowDetails] = useState(false);
+
+ const columnHelper = createColumnHelper<BucketTask>();
+ const columns = [
+ columnHelper.display({
+ id: "index",
+ header: "#",
+ cell: ({ row }) => row.index + 1,
+ size: 25,
+ meta: {
+ align: "center",
+ },
+ }),
+ columnHelper.accessor("source", {
+ header: () => "Marketplace",
+ cell: (props) => {
+ const s = props.getValue();
+ return formatSource(s);
+ },
+ size: 85,
+ meta: {
+ align: "left",
+ },
+ }),
+ columnHelper.accessor("id", {
+ header: () => "Survey ID",
+ cell: (props) => {
+ return truncate(props.getValue(), 6, "*****").toUpperCase();
+ },
+ size: 70,
+ meta: {
+ align: "left",
+ },
+ }),
+ columnHelper.accessor("payout", {
+ header: () => "Amount",
+ cell: (props) => {
+ const val = props.renderValue() as number;
+ return formatCentsToUSD(val);
+ },
+ size: 50,
+ meta: {
+ align: "center",
+ },
+ }),
+ columnHelper.accessor("loi", {
+ header: () => "Duration",
+ cell: (props) => {
+ const val = props.renderValue() as number;
+ return `${Math.round(val / 60)} min`;
+ },
+ size: 50,
+ meta: {
+ align: "center",
+ },
+ }),
+ ];
+
+ const table = useReactTable({
+ data: bucket.contents,
+ columns: columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+
+ return (
+ <>
+ <div
+ className="w-full text-center text-[8px] text-emerald-600
rounded py-2 my-1
hover:cursor-pointer hover:text-emerald-700 hover:underline hover:bg-emerald-200
"
- onClick={() => setShowDetails(!showDetails)}
- >
- ({showDetails ? 'Hide' : 'Show'} details of surveys in this bucket)
- </div>
-
- {showDetails && (
- <div className="w-full border-t-1 border-emerald-200 py-1 my-0 flex justify-center">
- <table className="text-[10px] text-emerald-900 table-fixed border-collapse">
- <thead className="font-bold">
- {table.getHeaderGroups().map((headerGroup) => (
-
- <tr key={headerGroup.id}>
- {headerGroup.headers.map((header) => {
- const align = header.column.columnDef.meta?.align || 'left';
- const alignClass = align === 'center' ? 'text-center' : align === 'right' ? 'text-right' : 'text-left';
-
- return (
- <th
- key={header.id}
- className={`p-0 m-0 ${alignClass}`}
- style={{
- width: `${header.column.getSize()}px`,
- }}
- >
- {flexRender(
- header.column.columnDef.header,
- header.getContext(),
- )}
- </th>
- )
- })}
- </tr>
- ))}
- </thead>
- <tbody>
- {table.getRowModel().rows.map((row) => (
- <tr key={row.id}>
- {row.getVisibleCells().map((cell) => {
- const align = cell.column.columnDef.meta?.align || 'left';
- const alignClass = align === 'center' ? 'text-center' :
- align === 'right' ? 'text-right' : 'text-left';
-
- return (
- <td key={cell.id}
- className={`p-0 ${alignClass}`}
- style={{
- width: `${cell.column.getSize()}px`,
- }}
- >
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
- </td>
- )
- })}
- </tr>
- ))}
- </tbody>
-
- </table>
- </div>
- )}
- </>
- )
+ onClick={() => setShowDetails(!showDetails)}
+ >
+ ({showDetails ? "Hide" : "Show"} details of surveys in this bucket)
+ </div>
+
+ {showDetails && (
+ <div className="w-full border-t-1 border-emerald-200 py-1 my-0 flex justify-center">
+ <table className="text-[10px] text-emerald-900 table-fixed border-collapse">
+ <thead className="font-bold">
+ {table.getHeaderGroups().map((headerGroup) => (
+ <tr key={headerGroup.id}>
+ {headerGroup.headers.map((header) => {
+ const align = header.column.columnDef.meta?.align || "left";
+ const alignClass =
+ align === "center"
+ ? "text-center"
+ : align === "right"
+ ? "text-right"
+ : "text-left";
+
+ return (
+ <th
+ key={header.id}
+ className={`p-0 m-0 ${alignClass}`}
+ style={{
+ width: `${header.column.getSize()}px`,
+ }}
+ >
+ {flexRender(
+ header.column.columnDef.header,
+ header.getContext(),
+ )}
+ </th>
+ );
+ })}
+ </tr>
+ ))}
+ </thead>
+ <tbody>
+ {table.getRowModel().rows.map((row) => (
+ <tr key={row.id}>
+ {row.getVisibleCells().map((cell) => {
+ const align = cell.column.columnDef.meta?.align || "left";
+ const alignClass =
+ align === "center"
+ ? "text-center"
+ : align === "right"
+ ? "text-right"
+ : "text-left";
+
+ return (
+ <td
+ key={cell.id}
+ className={`p-0 ${alignClass}`}
+ style={{
+ width: `${cell.column.getSize()}px`,
+ }}
+ >
+ {flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext(),
+ )}
+ </td>
+ );
+ })}
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+ )}
+ </>
+ );
};
const SurveyEnter = () => {
- const dispatch = useAppDispatch()
- const loi = useAppSelector(state => state.app.loi)
- const bpuid = useAppSelector(state => state.app.bpuid)
-
- const available_cnt = useAppSelector(state => getAvailabilityCount(state))
- const buckets = useAppSelector(state => state.app.currentBuckets)
- const bucket = useAppSelector(state => selectBucket(state))
- const isLow = useAppSelector(state => isLowBalance(state))
-
- useEffect(() => {
- if (!bpuid) return;
-
- new OfferwallApi().topNPlusBlockOfferwallProductIdOfferwallD48cce47Get(
- bpid, // productId
- bpuid, // bpuid
- undefined, // ip
- undefined, // countryIso
- undefined, // languages
- undefined, // behavior
- undefined, // minPayout
- loi, //duration
- 1 // nBins
- ).then(res => {
- const top_n_res = res.data.offerwall as TopNPlusBlockOfferWall;
- dispatch(setAvailabilityCount(top_n_res.availability_count))
- if (top_n_res.attempted_live_eligible_count) {
- dispatch(setAttemptedLiveEligibleCount(top_n_res.attempted_live_eligible_count))
- }
- dispatch(setCurrentBuckets(top_n_res.buckets))
- dispatch(setOfferwallReasons(top_n_res.offerwall_reasons ?? []))
- });
- }, [loi, bpuid]);
-
-
- const start_survey = () => {
- if (!bucket?.uri) return;
-
- dispatch(setEnteredTimestamp());
- window.open(bucket.uri, '_blank');
- }
-
- if (buckets === undefined) {
- return <SurveyLoading />
- }
-
- if (available_cnt === 0 || buckets.length === 0 || !bucket) {
- return <NoSurveys />
- }
-
- return (
- <>
- {isLow && (
- <div className="
+ const dispatch = useAppDispatch();
+ const loi = useAppSelector((state) => state.app.loi);
+ const { data: user } = useGetMeQuery();
+
+ const available_cnt = useAppSelector((state) => getAvailabilityCount(state));
+ const buckets = useAppSelector((state) => state.app.currentBuckets);
+ const bucket = useAppSelector((state) => selectBucket(state));
+ const isLow = useAppSelector((state) => isLowBalance(state));
+
+ useEffect(() => {
+ if (!user?.product_user_id) return;
+
+ new OfferwallApi()
+ .topNPlusBlockOfferwallProductIdOfferwallD48cce47Get(
+ bpid, // productId
+ // "7d9240132c695c05cd0ba47e2580158719f8215b",
+ // "71.225.51.26",
+ user.product_user_id,
+ undefined, // ip
+ undefined, // countryIso
+ undefined, // languages
+ undefined, // behavior
+ undefined, // minPayout
+ loi, //duration
+ 1, // nBins
+ )
+ .then((res) => {
+ const top_n_res = res.data.offerwall as TopNPlusBlockOfferWall;
+ dispatch(setAvailabilityCount(top_n_res.availability_count));
+ if (top_n_res.attempted_live_eligible_count) {
+ dispatch(
+ setAttemptedLiveEligibleCount(
+ top_n_res.attempted_live_eligible_count,
+ ),
+ );
+ }
+ dispatch(setCurrentBuckets(top_n_res.buckets));
+ dispatch(setOfferwallReasons(top_n_res.offerwall_reasons ?? []));
+ });
+ }, [loi, user?.product_user_id]);
+
+ const start_survey = () => {
+ if (!bucket?.uri) return;
+
+ dispatch(setEnteredTimestamp());
+ window.open(bucket.uri, "_blank");
+ };
+
+ if (buckets === undefined) {
+ return <SurveyLoading />;
+ }
+
+ if (available_cnt === 0 || buckets.length === 0 || !bucket) {
+ return <NoSurveys />;
+ }
+
+ return (
+ <>
+ {isLow && (
+ <div
+ className="
border-8 border-rose-500 rounded py-2
- bg-rose-400 text-rose-700">
- <h2 className="text-center text-xl font-bold text-white">
- Your balance is low.
- </h2>
- <p className="px-4 py-2 text-center text-sm font-medium text-white">
- You may continue to attempt surveys, but you will be
- advised to return the HIT if your survey attempt does
- not result in a complete.
- </p>
- <p className="px-4 py-2 text-center text-sm font-bold text-white">
- HIT submissions with a balance exceeding -$1.00 will
- return in rejected assignments.
- </p>
- </div>
- )}
-
- <LOISelect />
- <div
- onClick={start_survey}
- className="
+ bg-rose-400 text-rose-700"
+ >
+ <h2 className="text-center text-xl font-bold text-white">
+ Your balance is low.
+ </h2>
+ <p className="px-4 py-2 text-center text-sm font-medium text-white">
+ You may continue to attempt surveys, but you will not earn an
+ attempt credit if your survey attempt does not result in a complete.
+ </p>
+ <p className="px-4 py-2 text-center text-sm font-bold text-white">
+ Attempts with a balance exceeding -$1.00 will not be issued an
+ attempt credit.
+ </p>
+ </div>
+ )}
+
+ <LOISelect />
+ <div
+ onClick={start_survey}
+ className="
border-8 border-emerald-400 rounded py-0 my-2
- hover:cursor-pointer hover:bg-emerald-400 hover:text-emerald-50">
- <p className="py-2 text-center text-3xl font-semibold">
- <a
- target="_blank"
- rel="noopener noreferrer">
- Start Task
- </a>
- </p>
- </div>
- <BucketDetails />
-
- <div className="border-2 border-emerald-200 rounded py-2 m-0">
- <p className="text-emerald-700 text-sm text-center font-medium px-2 m-0">
- <Markdown>
- {bucket.eligibility_explanation}
- </Markdown>
- </p>
- </div>
- </>
- )
+ hover:cursor-pointer hover:bg-emerald-400 hover:text-emerald-50"
+ >
+ <p className="py-2 text-center text-3xl font-semibold">
+ <a target="_blank" rel="noopener noreferrer">
+ Start Task
+ </a>
+ </p>
+ </div>
+ <BucketDetails />
+
+ <div className="border-2 border-emerald-200 rounded py-2 m-0">
+ <p className="text-emerald-700 text-sm text-center font-medium px-2 m-0">
+ <Markdown>{bucket.eligibility_explanation}</Markdown>
+ </p>
+ </div>
+ </>
+ );
};
-
const Work = () => {
- const entered = useAppSelector(state => state.app.currentBucketEntered)
- const assignment_id = useAppSelector(state => state.app.assignment_id)
-
- if (!assignment_id) {
- return (
- <p className="text-center text-2xl py-3 text-red-800 font-semibold">
- No Assignment ID found. Please access this page through
- the Amazon Mechanical Turk platform.
- </p>
- )
- }
-
- return (
- <>
- {entered ? (
- <SurveyMonitor />
- ) : (
- <SurveyEnter />
- )}
- </>
- )
+ const entered = useAppSelector((state) => state.app.currentBucketEntered);
+ // const assignment_id = useAppSelector((state) => state.app.assignment_id);
+ // if (!assignment_id) {
+ // return (
+ // <p className="text-center text-2xl py-3 text-red-800 font-semibold">
+ // No Assignment ID found. Please access this page through the Amazon
+ // Mechanical Turk platform.
+ // </p>
+ // );
+ // }
+
+ const { data: user, isLoading, isError } = useGetMeQuery();
+ // const location = useLocation();
+
+ if (isLoading) return <div>Loading...</div>;
+
+ if (isError || !user) {
+ return <Preview />;
+ }
+
+ return <>{entered ? <SurveyMonitor /> : <SurveyEnter />}</>;
};
-
-export default Work; \ No newline at end of file
+export default Work;
diff --git a/jb-ui/src/store.ts b/jb-ui/src/store.ts
index 7b4d3e3..081de9f 100644
--- a/jb-ui/src/store.ts
+++ b/jb-ui/src/store.ts
@@ -1,32 +1,38 @@
-import appReducers from "@/models/appSlice"
-import grlStatsReducers from "@/models/grlStatsSlice"
-import grlEventsReducers from "@/models/grlEventsSlice"
-import profilingQuestionsReducers from "@/models/profilingQuestionsSlice"
-import type { Action, ThunkAction } from '@reduxjs/toolkit'
-import { configureStore } from '@reduxjs/toolkit'
+import appReducers from "@/models/appSlice";
+import grlStatsReducers from "@/models/grlStatsSlice";
+import grlEventsReducers from "@/models/grlEventsSlice";
+import { authApi } from "@/models/authAPI";
+import profilingQuestionsReducers from "@/models/profilingQuestionsSlice";
+import cashoutMethodReducers from "@/models/cashoutMethodsSlice";
+import type { Action, ThunkAction } from "@reduxjs/toolkit";
+import { configureStore } from "@reduxjs/toolkit";
export const store = configureStore({
- reducer: {
- app: appReducers,
- stats: grlStatsReducers,
- events: grlEventsReducers,
- profilingQuestions: profilingQuestionsReducers,
- }
-})
+ reducer: {
+ app: appReducers,
+ // auth: authReducers,
+ [authApi.reducerPath]: authApi.reducer,
+ stats: grlStatsReducers,
+ events: grlEventsReducers,
+ profilingQuestions: profilingQuestionsReducers,
+ cashoutMethods: cashoutMethodReducers,
+ },
+ middleware: (getDefault) => getDefault().concat(authApi.middleware),
+});
// Infer the type of `store`
-export type AppStore = typeof store
+export type AppStore = typeof store;
// Infer the `AppDispatch` type from the store itself
-export type AppDispatch = typeof store.dispatch
+export type AppDispatch = typeof store.dispatch;
// Same for the `RootState` type
-export type RootState = ReturnType<typeof store.getState>
+export type RootState = ReturnType<typeof store.getState>;
// Define a reusable type describing thunk functions
export type AppThunk<ThunkReturnType = void> = ThunkAction<
- ThunkReturnType,
- RootState,
- unknown,
- Action
->
+ ThunkReturnType,
+ RootState,
+ unknown,
+ Action
+>;
diff --git a/jb-ui/src/types/authApi.ts b/jb-ui/src/types/authApi.ts
new file mode 100644
index 0000000..19aeee0
--- /dev/null
+++ b/jb-ui/src/types/authApi.ts
@@ -0,0 +1,6 @@
+export interface User {
+ email: string;
+ display_name: string | null;
+ blocked: boolean;
+ product_user_id: string;
+}
diff --git a/jb-ui/src/vite-env.d.ts b/jb-ui/src/vite-env.d.ts
index 11d7a7a..93dc3cc 100644
--- a/jb-ui/src/vite-env.d.ts
+++ b/jb-ui/src/vite-env.d.ts
@@ -1,17 +1,17 @@
/// <reference types="vite/client" />
interface ViteTypeOptions {
- // By adding this line, you can make the type of ImportMetaEnv strict
- // to disallow unknown keys.
- // strictImportMetaEnv: unknown
+ // By adding this line, you can make the type of ImportMetaEnv strict
+ // to disallow unknown keys.
+ // strictImportMetaEnv: unknown
}
interface ImportMetaEnv {
- readonly VITE_BASENAME: string
- readonly VITE_BPID: string
- readonly VITE_TAG_MANAGER: string
+ readonly VITE_BASENAME: string;
+ readonly VITE_BPID: string;
+ readonly VITE_TAG_MANAGER: string;
}
interface ImportMeta {
- readonly env: ImportMetaEnv
-} \ No newline at end of file
+ readonly env: ImportMetaEnv;
+}
diff --git a/jb-ui/tests/base.test.ts b/jb-ui/tests/base.test.ts
index e2f56a6..cd818d9 100644
--- a/jb-ui/tests/base.test.ts
+++ b/jb-ui/tests/base.test.ts
@@ -1,3 +1,3 @@
-test('1 + 1 equals 2', () => {
- expect(1 + 1).toBe(2);
-}); \ No newline at end of file
+test("1 + 1 equals 2", () => {
+ expect(1 + 1).toBe(2);
+});
diff --git a/jb-ui/tests/setupTests.ts b/jb-ui/tests/setupTests.ts
index 8f2609b..1dd407a 100644
--- a/jb-ui/tests/setupTests.ts
+++ b/jb-ui/tests/setupTests.ts
@@ -2,4 +2,4 @@
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
-import '@testing-library/jest-dom';
+import "@testing-library/jest-dom";
diff --git a/jb-ui/vite.config.ts b/jb-ui/vite.config.ts
index 6b0e530..2336e4a 100644
--- a/jb-ui/vite.config.ts
+++ b/jb-ui/vite.config.ts
@@ -1,62 +1,56 @@
-import react from "@vitejs/plugin-react"
-import {defineConfig} from "vite"
-import path from 'path';
-import tailwindcss from '@tailwindcss/vite'
-
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+import path from "path";
+import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
- plugins: [
- react(),
- tailwindcss(),
-
- ],
+ plugins: [react(), tailwindcss()],
- resolve: {
- alias: {
- '@': path.resolve(__dirname, './src'),
- },
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
},
-
- server: {
- // host: "0.0.0.0",
- // port: 8001,
-
- // This forwards requests to the FastAPI development server
- // that must also be running
- proxy: {
- '^/(status|statuses|report|survey)(/|$)': {
- target: 'http://localhost:8000',
- changeOrigin: true,
- }
- }
+ },
+
+ server: {
+ // host: "0.0.0.0",
+ // port: 8001,
+
+ // This forwards requests to the FastAPI development server
+ // that must also be running
+ proxy: {
+ "^/(auth|status|statuses|report|survey)(/|$)": {
+ target: "http://localhost:8000",
+ changeOrigin: true,
+ },
},
+ },
- define: {
- 'process.env.NODE_ENV': JSON.stringify('production')
- },
+ define: {
+ "process.env.NODE_ENV": JSON.stringify("production"),
+ },
- build: {
- cssCodeSplit: false,
- lib: {
- name: "jb-ui",
- entry: 'src/main.tsx',
+ build: {
+ cssCodeSplit: false,
+ lib: {
+ name: "jb-ui",
+ entry: "src/main.tsx",
+ },
+ rollupOptions: {
+ output: {
+ entryFileNames: "james-billings.js",
+ assetFileNames: (assetInfo) => {
+ if (assetInfo.names[0].endsWith(".css")) {
+ return "james-has-style.css";
+ }
+
+ return "assets/[name].[hash][extname]";
},
- rollupOptions: {
- output: {
- entryFileNames: 'james-billings.js',
- assetFileNames: (assetInfo) => {
-
- if (assetInfo.names[0].endsWith('.css')) {
- return 'james-has-style.css';
- }
-
- return 'assets/[name].[hash][extname]';
- },
- globals: {
- react: 'React',
- 'react-dom': 'ReactDOM'
- }
- }
- }
- }
-}) \ No newline at end of file
+ globals: {
+ react: "React",
+ "react-dom": "ReactDOM",
+ },
+ },
+ },
+ },
+});