---
title: "Apply an affiliate-link recommendation to one component and country"
method: POST
path: "/api/admin/affiliate-apply"
tags: ["admin-affiliate"]
---

# Apply an affiliate-link recommendation to one component and country

`POST /api/admin/affiliate-apply`

## Request

- Base URL: `https://voltplan.app`
- URL: `https://voltplan.app/api/admin/affiliate-apply`
- Auth: HTTP bearer

Upserts the single `affiliate_links` row for (`componentId`, `country`) with the PocketBase superuser client: the first matching row is updated, otherwise a row is created. `country` defaults to `universal`.

Per `actionType`:
- `use_existing_url` (needs `preferredUrl`) and `search_and_apply` (needs `researchedUrl`) store the expanded URL with `unavailable: false`. A bare 10-character ASIN becomes a product URL on the country's Amazon marketplace (`buildProductUrl`); any other URL gets that marketplace's affiliate tag (`applyRegionalTag`). `universal` uses the `de` marketplace.
- `mark_unavailable` stores `url: null, unavailable: true`.
- `delete_link` deletes the `affiliate_links` record `linkId` (its country is not checked).
- `keep_search_fallback` writes nothing.
- `manual_review` and `keep_external` are rejected with 400.

`componentId` is required for every action, including `delete_link`. `componentName`, `unavailable` and `searchQuery` are accepted and ignored.

## Request body

- AdminAffiliateApplyRequest
  - `componentId` string, required: Id of the `components` record.
  - `componentName` string: Accepted, not read.
  - `country` 'universal' | 'de' | 'us' | 'uk' | 'fr' | 'es' | 'it' | 'au'
  - `unavailable` boolean: Accepted, not read; use `actionType: mark_unavailable`.
  - `actionType` 'use_existing_url' | 'search_and_apply' | 'keep_search_fallback' | 'keep_external' | 'manual_review' | 'mark_unavailable' | 'delete_link', required
  - `preferredUrl` string: ASIN or URL; required for `use_existing_url`.
  - `researchedUrl` string: ASIN or URL; required for `search_and_apply`.
  - `searchQuery` string: Accepted, not read.
  - `linkId` string: Id of the `affiliate_links` record; required for `delete_link`.

## Response `200`

Recommendation applied.

- AdminAffiliateApplyResponse
  - `success` unknown, required
  - `mode` 'existing' | 'search_result' | 'unavailable' | 'search_fallback' | 'deleted', required: `use_existing_url` → `existing`, `search_and_apply` → `search_result`, `mark_unavailable` → `unavailable`, `keep_search_fallback` → `search_fallback`, `delete_link` → `deleted`.
  - `url` string: Stored URL; only for `existing` and `search_result`.
  - `country` 'universal' | 'de' | 'us' | 'uk' | 'fr' | 'es' | 'it' | 'au': Absent for `deleted`.

## Other responses

- `400`: Missing `componentId` or `actionType`, an action that must not be auto-applied, a missing action-specific field, or an unknown `actionType`.
- `403`: Admin access required. Returned for a missing, invalid or expired bearer token as well as for a valid token whose user lacks `is_admin=true`; admin endpoints never answer 401.
- `500`: Malformed JSON body, PocketBase error, or admin credentials (`POCKETBASE_ADMIN_EMAIL`, `POCKETBASE_ADMIN_PASSWORD`) not configured; `error` carries the thrown message.

---

[API](https://skmtc.dev/voltplan/apis/voltplan-api.md) · [All operations](https://skmtc.dev/voltplan/apis/voltplan-api/llms.txt) · [OpenAPI document](https://skmtc.dev/voltplan/apis/voltplan-api/revisions/575b86a7af92?raw)
