Survey campaign API
The advertiser survey API is mounted at /api/v1/campaigns. It is intended for approved advertiser accounts integrating from their server. Dashboard users can follow the survey campaign workflow without calling these endpoints.
Authentication
Send your advertiser X-Api-Key over HTTPS. Requests also require a URL signature in the enc query parameter, derived from the advertiser secret and request body. The service rejects missing keys, unknown keys, pending advertiser accounts, and invalid signatures. Keep the key and secret on your server and validate the exact signing output with your RapidoReach integration contact before connecting traffic. Do not reuse a publisher application API key.
The current signing implementation hashes the full request URL without a query string, then the JSON serialization of a nonempty body, then the advertiser secret. It appends the hex digest as the sole ?enc=... query value. The request scheme and host must match what the server reconstructs from its forwarded protocol and Host header. Body serialization must match what the server receives. The account's configured url_security_encryption_type selects SHA-1, SHA-256, or SHA3-256; the helper falls back to SHA3-256 for an unrecognized value. Confirm your account's configured algorithm before using the sample below. Test signing in development before automating a write; do not add other query parameters to a signed URL.
For a current SHA3-256 account, a server can construct a request as follows. Confirm the algorithm and base URL for your account before use; this sample makes no network request.
const { createHash } = require('node:crypto');
const baseUrl = 'https://YOUR_DEVELOPMENT_HOST/api/v1/campaigns/create';
const body = {
name: 'Example study', country_language_id: 'YOUR_MARKET_ID',
cpi: 1.5, length_of_interview: 10, conversion: 20,
start_date: '2026-10-01', end_date: '2026-10-15',
survey_live_link: 'https://survey.example/live?transaction={transaction_id}',
survey_test_link: 'https://survey.example/test?transaction={transaction_id}',
max_daily_completes: 50,
};
const json = JSON.stringify(body);
const digest = createHash('sha3-256')
.update(baseUrl + json + process.env.RAPIDOREACH_ADVERTISER_SECRET)
.digest('hex');
const signedUrl = `${baseUrl}?enc=${digest}`;
// Send json as the POST body and X-Api-Key from protected server configuration.
Both survey links must contain the exact {transaction_id} macro. Preserve its resolved value throughout the survey and result redirects. Confirm accepted link formats with the dashboard and a development request.
Campaign endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /getcampaigns | List campaigns visible to the authenticated creator |
| POST | /searchcampaigns | Search campaigns |
| POST | /create | Create a draft campaign |
| GET | /:campaignId | Read a campaign |
| PUT | /:campaignId | Update a campaign, subject to route policy |
| POST | /clonecampaigns | Clone a campaign for a new study |
| DELETE | /:campaignId | Delete a campaign where policy allows |
Create and update validate the live and test survey link templates. A name on create must be at least four characters. Keep the live and test URLs separate and verify redirects before funding. Treat campaign IDs as opaque, and keep each advertiser's IDs and credentials separate. Do not use an ID alone as your own authorization check.
Create request fields
POST /create accepts a JSON body with the project fields below. Values must match the same market, pricing, and link assumptions used in the dashboard.
| Field | Purpose |
|---|---|
name | Internal campaign name, at least four characters |
country_language_id | Target country and language identifier |
cpi | Cost per completed interview |
length_of_interview | Expected minutes per interview |
conversion | Expected completion percentage |
start_date, end_date | Field dates |
survey_live_link, survey_test_link | Validated live and test survey link templates |
max_daily_completes | Daily completion limit |
supported_devices | Device eligibility list |
research_category, research_industry, campaign_manager, tags | Optional project metadata |
On success, create returns HTTP 201 with campaign and creator objects; the creator response includes a test_redirect_url. Use that test URL to check outcomes before funding. Invalid input or signing prevents creation. Treat response IDs and test URLs as opaque; do not build new URLs from their internal structure.
{
"message": "Campaign created successfully",
"campaign": {"_id": "CAMPAIGN_ID", "name": "Example study"},
"creator": {"_id": "ADVERTISER_USER_ID", "test_redirect_url": "/test/survey/..."}
}
Quotas and screening
| Method | Path | Purpose |
|---|---|---|
| GET | /:campaignId/getcampaignquota | List campaign quotas |
| POST | /:campaignId/campaignsquota | Create a quota |
| GET / PUT / DELETE | /:campaignId/campaignsquota/:campaignQuotaId | Read, update, or remove a quota |
| GET | /:campaignId/getcustomquestions | List custom screeners |
| POST | /:campaignId/customquestion | Create a screener |
| GET / PUT / DELETE | /:campaignId/customquestion/:customquestionId | Read, update, or remove a screener |
| POST | /:campaignId/clonecampaignsquota | Clone a campaign quota |
| GET | /:campaignId/campaignsquota/:campaignQuotaId/getcampaignsqualifications | List qualifications |
| POST | /:campaignId/campaignsquota/:campaignQuotaId/campaignsqualification | Add a qualification |
| GET / PUT / DELETE | /:campaignId/campaignsquota/:campaignQuotaId/campaignsqualification/:campaignQualificationsId | Read, update, or remove a qualification |
| POST | /cq/:customquestionId/createoption | Add a screener answer option |
| PUT / DELETE | /cq/:customquestionId/option/:option_id | Update or remove an answer option |
POST /:campaignId/campaignsquota accepts name and num_respondents in JSON and returns 201 with campaignQuota. POST /:campaignId/clonecampaignsquota takes {"quotaId":"SOURCE_QUOTA_ID"}. A new custom question and a new answer option are initialized with defaults; update the returned IDs with the question and answer text and acceptance rules before using them to screen respondents. Read the saved quota and question back before assigning supply or funding.
Additional endpoints: POST /listcountrylanguage lists supported markets; POST /getProfilingQuestionsForTargeting returns profiling catalog data; GET /:campaignId/getcustomquestionsforprofiling returns campaign screeners for profiling; GET /downloadresponses downloads responses; GET /invoices lists invoices. These depend on campaign state and account configuration. Start with reads in development, then test a complete draft, quota, screener, redirect, and funding flow before API writes. API creation alone does not activate or fund a campaign. See survey API errors and checks.