Notice campaigns
The endpoint that hands a notice campaign's links to your sender, and the hosted notice page each link opens, with responses, errors and limits.
A notice campaign gives each person a single-use link to one published notice. These are the endpoint your sender reads the links from, and the page a link opens. Paths are relative to https://console.dpconsent.com/consent/sdk/v1. The task is in Send notice links from your own gateway.
Endpoints#
GET /campaigns/{campaignId}/batches/{batchId}/links#
Returns one page of a batch's links that are not used, replaced or revoked.
| Key | Scope | Idempotency-Key |
Webhook sent |
|---|---|---|---|
| Secret | campaigns:links |
Ignored | None |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
campaignId |
string | Yes | Path parameter. The campaign, from campaign.batch_issued. |
batchId |
string | Yes | Path parameter. The batch. |
after |
string | No | The next value of the previous page. |
limit |
integer, 1 to 5,000 | No | Links in the page. Default 1,000. |
Request
CAMPAIGN="https://console.dpconsent.com/consent/sdk/v1/campaigns/$CAMPAIGN_ID"
curl "$CAMPAIGN/batches/$BATCH_ID/links?limit=5000" \
-H "Authorization: Bearer $PIEDAP_SENDER_KEY"Response
200, with Cache-Control: no-store:
{
"campaignId": "9d1f2a6e-4b3c-4e8f-a1d2-7c5b0e9f3a41",
"batchId": "c2e8b4d0-1f7a-4a39-9e65-3b0d8c2f6a17",
"sequence": 1,
"expiresOn": "2027-01-01T06:30:00.000Z",
"availableUntil": "2026-10-10T06:30:00.000Z",
"links": [
{
"linkId": "5b7e9c21-0d4a-4f6b-8e3c-2a1f9d7b6c50",
"reference": "CRM-104233",
"fingerprint": "a71c…",
"subjectType": "USER_ID",
"language": "hi",
"url": "https://console.dpconsent.com/consent/sdk/v1/n/Q3vT9xKp2mLs8RbYw4ZcHa"
}
],
"next": null
}| Field | Type | Description |
|---|---|---|
sequence |
integer | The batch's number in the campaign. |
expiresOn |
time | When the links of the batch stop working. |
availableUntil |
time | Until when the links can be read, 7 days after the batch was issued. |
links[].linkId |
string | Keep it with the message, for delivery reports. |
links[].reference |
string or null | The reference you gave the row. |
links[].fingerprint |
string or null | The person's subject fingerprint under your project's key. |
links[].subjectType |
string | USER_ID, EMAIL or PHONE: the type of the person's first identifier. |
links[].language |
string | The language the page opens in. |
links[].url |
string | The link to send. Anyone holding it can answer for that person. |
next |
string or null | Send it as after for the next page. null on the last page. |
Errors
| Status | Code | When |
|---|---|---|
403 |
SCOPE_REQUIRED |
A publishable key, or a secret key without campaigns:links. |
403 |
PROPERTY_NOT_FOR_KEY |
The key is tied to another property than the campaign's. |
404 |
CAMPAIGN_NOT_FOUND |
No such campaign, or it belongs to the other environment than the key. |
404 |
BATCH_NOT_FOUND |
No such batch in the campaign. |
409 |
BATCH_NOT_READY |
The links are still being made. Wait for campaign.batch_issued. |
410 |
LINKS_NO_LONGER_AVAILABLE |
More than 7 days passed since the batch was issued. Issue new links to people who still need one. |
429 |
None | The key's budget for calls on a person, 60 a minute, was reached. |
Each call writes an audit entry, CAMPAIGN_LINKS_READ, with the key's name and the number of links.
GET /n/{token}#
The hosted notice page a link opens. It needs no key: the token in the link is the credential.
| Key | Scope | Idempotency-Key |
Webhook sent |
|---|---|---|---|
| None | None | Ignored | None |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
token |
string | Yes | Path parameter. The 22 characters at the end of the link. |
lang |
string | No | A language the notice is written in. Otherwise the person's language from the upload, then the notice's default. |
Response
An HTML page. Opening it changes nothing, so a mail filter that opens links does not answer for anyone. The wording around your notice is a neutral default that awaits review by your counsel.
| Status | Page |
|---|---|
200 |
The notice with I have read this notice and Withdraw my consent, or Already answered for a used link |
400 |
The link is not valid, or the person was erased |
410 |
Link expired, Link replaced or Notice closed |
429 |
Too many requests from this address |
POST /n/{token}#
Records the person's answer. The page's two forms send it.
| Key | Scope | Idempotency-Key |
Webhook sent |
|---|---|---|---|
| None | None | Ignored | campaign.withdrawn for a withdrawal |
Parameters
application/x-www-form-urlencoded:
| Name | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | acknowledge or withdraw. |
lang |
string | No | The language of the page the person answered on. |
Response
An HTML page, with the statuses of GET, and 500 only when the answer could not be stored.
| Action | What happens |
|---|---|
acknowledge |
The answer is stored on the campaign. No consent record is read or changed, and no webhook is sent. |
withdraw |
The answer is stored, then each record recorded under the person's first identifier, or linked to it, is withdrawn as a withdrawal from the person: on the campaign's property or in the whole project, as When a person withdraws is set. A record answered again after the click is left as it is. Each record withdrawn sends consent.withdrawn. When all are done, campaign.withdrawn is sent. |
A withdrawal that cannot be applied at once is completed by a job that runs every 15 seconds, once the answer is a minute old. Until then a consent check answers withdrawn when it names the person's first identifier, or finds a record recorded under or linked to it. A second click with the same answer shows the same result page.
Every page is sent with these headers:
Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline';
form-action 'self'; base-uri 'none'; frame-ancestors 'none'
Referrer-Policy: no-referrer
Cache-Control: no-store
X-Content-Type-Options: nosniff
X-Robots-Tag: noindexThe page cannot be framed, so no site can wrap a withdraw button.
Limits#
| Limit | Value |
|---|---|
| Link life | 60 to 90 days, 90 unless set on the campaign |
| Links readable after a batch is issued | 7 days |
| Links in one batch | 100,000 |
| Links in one page | 5,000 |
| People in one file | 200,000 |
| Identifiers for one person | 5: a customer id, email address or phone number |
| Reference | 64 characters, not an email address |
| Requests to the page from one address | 300 in 10 minutes |
| Unknown or malformed links from one address | 20 in 10 minutes |
People behind one mobile carrier address share the limits for one address.