Consent store integration via REST API
This section explains how to integrate and query the consent archive, which you need to store proof of the consent to personal data processing that users may have knowingly given while browsing your website.
This documentation describes the endpoints for managing consents within web spaces. The base URL of the API is
https://api.avacy.eu/:team/v4
Create a new consent for a specific web space
POST /webspaces/:id/consents
Route parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | The identifier of the web space on which the consent is created |
Authentication
The request requires an Access Key, sent in the Authorization: Bearer <token> header.
How to get the Access Key
- Log in to Avacy and open the web space on which you want to record consents.
- At the top right, click web space settings and then Avacy integration on your web space.
- Open the Access Keys tab and create a new access key, give it a name so you can recognize it (e.g. "WordPress plugin") and copy the code shown.
The code is shown only once: keys that have already been created are no longer visible. Only the most recently created key for the web space is valid: earlier keys are rejected with 403. If you generate a new one, update it everywhere it is used. If you delete the most recently created key, the previous one (if it still exists) becomes valid again.
A key is valid only for the web space it was generated for and does not expire.
Recording consents requires a plan that includes the consent archive. Otherwise the request is rejected with 403, for both form and banner.
Required headers
| Name | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer <token>, where <token> is the web space Access Key (see Authentication) |
Accept | string | Yes | Specifies the desired response format (application/json) |
Content-Type | string | Yes | Specifies the request content format (application/json) |
Request parameters (JSON format)
| Name | Type | Required | Description |
|---|---|---|---|
consent_type | string | Yes | The type of consent: form or banner |
optin | string | Yes | Consent status: accepted, rejected or partially_accepted |
identifier | string | No | Unique identifier of the subject providing consent |
ip_address | string | Yes for form | Required for forms. The recorded IP is the one the call comes from: if you call from your own server, report the contact's IP in consent_data |
consent_features | array, object or string | Yes for form | Purposes of the consent. As an array it lists the purposes for which consent was given. As an object it assigns each purpose its status, true (accepted) or false (refused or revoked): {"phone": true, "whatsapp": false}. Also accepts a comma-separated string ("a,b") |
consent_data | array or string | Yes for form | Consent data with label/value structure. Also accepts a string ("name=Mario,email=x") |
uuid | string | No | Consent identifier in UUID format. If omitted, Avacy generates it. Keep it if you need to revoke the consent (see Consent revocation) |
source | string | No | Source of consent (e.g. "website", "app") |
html_form | string | No | HTML representation of the consent form shown to the user |
versions | array | No | Not used |
- The recorded versions are those of the policies (privacy and cookie) generated by Avacy on the web space. If you use an external policy, include its details in
consent_data. - With
consent_type: bannerthe Access Key is not needed: Avacy checks that theOriginorRefererheader matches a domain of the web space. If both headers are missing the response is400; if neither matches, it is403. This check runs only in production. The Bearer token is required forform. - The Avacy banner also sends other
optinvalues (consent-all,reject-all,save-preferences,close-banner): they are internal to the banner and must not be used in integrations.
Example:
{
"consent_type": "form",
"optin": "accepted",
"ip_address": "192.168.1.20",
"consent_data": [
{
"label": "name",
"value": "Mario"
},
{
"label": "surname",
"value": "Rossi"
}
],
"identifier": "user-123",
"source": "website",
"consent_features": [
"privacy_policy",
"cookie_policy"
],
"html_form": "<p>We use cookies and other technologies...</p>",
"uuid": "550e8400-e29b-41d4-a716-446655440000"
}
To also record the refused purposes, pass consent_features as an object, with one entry for each purpose:
"consent_features": {
"phone": true,
"whatsapp": false,
"email": true
}
Successful Response
Code: 201 Created
{
"message": "Consent created successfully",
"data": {
"id": 123,
"webspace_id": 1,
"ip_address": "192.168.1.20",
"consent_type": "form",
"optin": "accepted",
"consent_data": [
{
"label": "name",
"value": "Mario"
},
{
"label": "surname",
"value": "Rossi"
}
],
"versions": [
{
"slug": "privacy_policy",
"link": "https://assets.example.com/policies/.../privacy_policy.html",
"date": "2025-05-15"
}
],
"identifier": "user-123",
"domain": null,
"source": "website",
"consent_features": [
"privacy_policy",
"cookie_policy"
],
"html_form": "<p>We use cookies and other technologies...</p>",
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2025-11-12T10:30:00.000000Z",
"updated_at": "2025-11-12T10:30:00.000000Z"
}
}
domain contains the request's Origin header (or Referer if Origin is missing). It is null if you call from your own server without these headers. In versions, date is the date and time the consent was recorded.
Error Response
| Code | When |
|---|---|
400 Bad Request | banner only: both Origin and Referer are missing |
403 Forbidden | Access Key missing or invalid (including a key replaced by a more recent one, or generated for another web space); for banner, a domain that doesn't belong to the web space; or a plan without the consent archive |
404 Not Found | The web space with the specified ID does not exist. You can't get this error with form: an id that doesn't match the key's web space returns 403 first |
422 Unprocessable Entity | Required fields are missing or invalid |
Listing, export, import and deletion
These endpoints work on the same web space (/webspaces/:id/consents) and require dashboard authentication: the Access Key is not accepted.
List consents
GET /webspaces/:id/consents
Paginated response, sorted by creation date descending. Filters available as query string:
| Parameter | Description |
|---|---|
identifier | Partial match on the identifier |
uuid | Partial match on the UUID |
type | form or banner |
optin | accepted, rejected or partially_accepted |
start, end | Creation date range (YYYY-MM-DD) |
consent_features | Case-insensitive partial match on the purposes |
domain | Partial match on the originating domain |
limit | Results per page (default 15) |
Export
GET /webspaces/:id/consents/export
Returns a .tsv file. It accepts the same filters as the list (except domain) and the ids parameter with comma-separated consent IDs. In the Optin column, accepted is exported as Yes and every other value as No, so partially_accepted can't be distinguished from rejected.
Import
POST /webspaces/:id/consents/import
Send a csv, tsv or txt file (max 10 MB) in the file field as multipart/form-data. Required columns: Identifier, Consent Type, IP Address, Created At, plus Optin. Invalid rows are skipped and reported in the errors field of the response.
IP Addressaccepts IPv4 addresses only: rows with an IPv6 address are skipped.Optinis imported asacceptedonly foryes,true,1,accepted,sìorsi. Any other value, includingpartially_accepted, is imported asrejected.- The response is
200if at least one row is imported, otherwise422.
Deletion
| Endpoint | Description |
|---|---|
DELETE /webspaces/:id/consents/:consent_id | Deletes one consent |
DELETE /webspaces/:id/consents/delete | Deletes the consents listed in consent_ids (an array in the request body). Returns 400 if the array is empty and 404 if no ID matches |
DELETE /webspaces/:id/consents | Bulk-deletes the consents matching the filters given in the query string |
Bulk deletion supports these filters: identifier, uuid, type, optin, start, end and consent_features. The domain filter is not available, and consent_features is case-sensitive here, unlike in the list.
DELETE /webspaces/:id/consents without filters deletes all the consents of the web space.
Consent revocation
There is no dedicated revocation endpoint. A consent is revoked by recording a new consent with POST /webspaces/:id/consents, as the Avacy banner does:
- Keep the
uuidyou receive in the response when the consent is created. - To revoke, send a new
POSTwith the sameuuidand the sameidentifier, and set the revoked purposes tofalseinconsent_features(as an object). The other fields that are required forform(optin,ip_address,consent_data) must be sent as in a creation.
The parts that change compared to the original consent:
{
"consent_type": "form",
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"identifier": "user-123",
"consent_features": {
"phone": false,
"whatsapp": false,
"email": true
}
}
The last recorded record is the one that applies: the previous ones stay in the archive as history and proof.
Do not use the deletion endpoints to revoke a consent: they delete the record, and the proof with it.