> For the complete documentation index, see [llms.txt](https://spree-finance.gitbook.io/spreefinance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://spree-finance.gitbook.io/spreefinance/spree-studio/campaigns-and-pending-sp.md).

# Campaigns & Pending SP

This guide walks through the operational lifecycle of a pSP campaign: create, issue, settle, clawback, recycle. For the conceptual model — why pSP exists, how budget recycling works — see [Pending SP (pSP)](/spreefinance/products/pending-sp.md).

## Lifecycle Mental Model

SP is the stable currency. pSP is conditional escrow.

1. You create a campaign with an SP budget.
2. You issue pSP to users.
3. Users that meet the campaign condition (hold N days, perform action X) get their pSP **settled** into SP and delivered to a destination address.
4. For pSP that goes unfulfilled, an admin **explicitly clawbacks** the balance back into the campaign budget. pSP does not auto-expire — it stays in the user's balance until an admin acts on it.

Each step is gated by a specific role. The role model lets you split operations across teams or partners — see [Whitelist Management → Partner A → Partner B](/spreefinance/spree-studio/whitelist-management.md#worked-example-partner-a--partner-b-partial-delegation) for the canonical delegation example.

## Create a Campaign

Required authority: `MANAGER_ROLE` or `CAMPAIGN_ADMIN_ROLE` on the PSPVault. `CAMPAIGN_ADMIN_ROLE` is auto-granted to your deployer wallet. The caller automatically becomes a per-campaign admin on the campaign they create (which lets them later configure delegated minters and per-campaign whitelists without needing additional grants).

The on-chain `createCampaign` call takes:

```solidity
createCampaign(
  bytes32 campaignId,
  uint256 spBudget,
  address[] settlementDestinations,
  address[] transferWhitelist,
  string metadata
)
```

| Path      | Where                                                                                                      |
| --------- | ---------------------------------------------------------------------------------------------------------- |
| Studio UI | `/sp/pending` → New campaign                                                                               |
| SDK       | `pendingSPVault.createCampaign(campaignId, spBudget, settlementDestinations, transferWhitelist, metadata)` |
| HTTP API  | `POST /studio/sdk/v1/tx/psp/create-campaign`                                                               |

`spBudget` must be funded — you transfer SP into the vault before or as part of campaign creation. Use `pendingSPVault.fundCampaign(campaignId, amount)` (HTTP: `POST /studio/sdk/v1/tx/psp/fund-campaign`) to top up an existing campaign.

## Issue pSP

Authority to call `mint(...)` comes from any of:

* `MANAGER_ROLE` on the PSPVault (no per-campaign limit, no budget limit beyond the campaign's `spBudget`).
* `ISSUING_ADMIN_ROLE` on the PSPVault — broad: the holder can mint into any active campaign on this vault, budget-limited only.
* Campaign admin status on a specific campaign — the campaign creator gets this automatically; additional admins can be added with `setCampaignAdmin`.
* A per-campaign delegated minter configuration set via `setMinter(campaignId, minter, limit, active=true)` — scoped to one campaign with a hard limit. See [Whitelist Management → Partner A → Partner B](/spreefinance/spree-studio/whitelist-management.md#worked-example-partner-a--partner-b-partial-delegation) for the canonical scoped-delegation pattern.

| Path      | Where                                                   |
| --------- | ------------------------------------------------------- |
| Studio UI | Campaign detail → Issue pSP                             |
| SDK       | `pendingSPVault.mint(campaignId, to, amount, metadata)` |
| HTTP API  | `POST /studio/sdk/v1/tx/psp/mint`                       |

Issuance is the high-frequency operation in a campaign. Most partners drive it from a backend service that watches user activity and calls `mint(...)` server-side via the SDK or HTTP API.

## Settle pSP → SP

Required role: `SETTLEMENT_ADMIN_ROLE`. The destination must be on the campaign's settlement whitelist (see [`updateSettlementWhitelist`](#per-campaign-whitelists)).

| Path      | Where                                                                   |
| --------- | ----------------------------------------------------------------------- |
| Studio UI | Campaign detail → Settle                                                |
| SDK       | `pendingSPVault.settle(holder, receiver, amount, campaignId, metadata)` |
| HTTP API  | `POST /studio/sdk/v1/tx/psp/settle`                                     |

Settlement converts pSP into SP and delivers it to the receiver address. Use the same address as the holder for direct claims, or a different address for redirect (e.g., to a custodian).

## Clawback Unfulfilled pSP

pSP does **not** auto-expire. Issued pSP stays in a user's balance indefinitely until an admin explicitly settles it (converts to SP, sends to a destination) or clawbacks it (returns the underlying SP to the campaign budget).

To clawback unfulfilled pSP — typically at the end of a campaign window or for a user that didn't meet the qualifying condition — an admin calls `expire(...)`:

| Path      | Where                                                         |
| --------- | ------------------------------------------------------------- |
| Studio UI | Campaign detail → Clawback / Expire                           |
| SDK       | `pendingSPVault.expire(holder, amount, campaignId, metadata)` |
| HTTP API  | `POST /studio/sdk/v1/tx/psp/expire`                           |

The clawed-back SP returns to the campaign budget. You can then issue new pSP from the recycled budget without depositing additional collateral.

Required role: `SETTLEMENT_ADMIN_ROLE`.

## Per-Campaign Whitelists

Each campaign has its own **settlement-destination whitelist** (which addresses can receive settled SP) and **transfer whitelist** (which addresses can hold pSP for this campaign). Both are set at `createCampaign` time and can be amended afterward:

| Operation                   | SDK                                                                      | HTTP API                                                 |
| --------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------- |
| Update settlement whitelist | `pendingSPVault.updateSettlementWhitelist(campaignId, account, allowed)` | `POST /studio/sdk/v1/tx/psp/update-settlement-whitelist` |
| Update transfer whitelist   | `pendingSPVault.updateTransferWhitelist(campaignId, account, allowed)`   | `POST /studio/sdk/v1/tx/psp/update-transfer-whitelist`   |

These per-campaign whitelists are independent of **mint** authorisation, which comes from `ISSUING_ADMIN_ROLE`, per-campaign admin status, or a per-campaign delegated-minter config (`setMinter`). See the worked example in [Whitelist Management](/spreefinance/spree-studio/whitelist-management.md#worked-example-partner-a--partner-b-partial-delegation) for how to scope all three.

## Required Roles by Step

| Step                                                            | Authority required                                                                                        |
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Create campaign                                                 | `MANAGER_ROLE` or `CAMPAIGN_ADMIN_ROLE` (creator becomes per-campaign admin automatically)                |
| Configure per-campaign minter / settlement / transfer whitelist | `MANAGER_ROLE` or per-campaign admin                                                                      |
| Set additional campaign admins                                  | `MANAGER_ROLE` or campaign creator                                                                        |
| Issue pSP                                                       | One of: `MANAGER_ROLE`, `ISSUING_ADMIN_ROLE`, per-campaign admin, or active per-campaign delegated minter |
| Settle pSP → SP                                                 | `MANAGER_ROLE` or `SETTLEMENT_ADMIN_ROLE`                                                                 |
| Clawback / expire                                               | `MANAGER_ROLE` or `SETTLEMENT_ADMIN_ROLE`                                                                 |
| Admin transfer between users                                    | `MANAGER_ROLE` or `TRANSFER_ADMIN_ROLE`                                                                   |

## Common Patterns

| Pattern          | Condition              | Issue when                     | Settle when                      |
| ---------------- | ---------------------- | ------------------------------ | -------------------------------- |
| Hold-and-release | Hold ≥ X SP for N days | User completes a target action | Hold duration validated on-chain |
| Swap-and-claim   | Complete N swaps       | User performs first swap       | Nth swap confirmed               |
| Event attendance | Attend N events        | Pre-event registration         | Attendance check-in              |
| Spend-and-earn   | Spend ≥ $X             | Purchase confirmation          | Refund window passes             |

## Related

* [Pending SP (pSP) concepts](/spreefinance/products/pending-sp.md)
* [Authority & Roles](/spreefinance/spree-studio/authority-and-roles.md) — delegating campaign roles
* [Whitelist Management](/spreefinance/spree-studio/whitelist-management.md) — the Partner A → Partner B walkthrough composes `ISSUING_ADMIN_ROLE` with per-campaign `setMinter` for scoped delegation
