> **Description:** Comprehensive guide to the Donations API, enabling customized post-donation experiences and management of both single and recurring donations.

# Donations API guide

Once you have access to the *Donations* product, you can use this API to pull donation payment reports and receive real-time webhook notifications about agreement changes.

## Integration steps

For a step-by-step walkthrough of getting your keys, requesting an access token, and calling the
Donations API endpoints, see the [Quick start guide](https://developer.vippsmobilepay.com/docs/APIs/donations-api/quick-start.md).

**Production only**

The Donations API is not available in the test environment. All requests in this guide use the production server, [`https://api.vipps.no`](https://api.vipps.no).

## How to get the API keys

Use a merchant-level API client to authenticate with the Donations API. Unlike other Vipps MobilePay API clients, this operates at the organization level rather than the sales unit level. A *Client ID* and *Client Secret* will be generated for you to use when you [request an access token](https://developer.vippsmobilepay.com/docs/APIs/donations-api/quick-start.md#step-2---get-an-access-token).

**To get the merchant-level keys:**

Generate the API client from the *Donations* tab in the [developer portal](https://portal.vippsmobilepay.com/). The tab is only visible after you have been approved for the *Donations* product.

1. Click *For developers* in the left sidebar.
2. Select the *Donations* tab.
3. Click *Generate*.

   Screenshot: Developer portal "Donations" tab showing "API access for Donations" with a "Generate an API client" section and a Generate button.

4. Copy your credentials and store them somewhere safe. The secret is shown only once.

   Screenshot: Donations API page after key generation showing the API client and a "Regenerate client secret" button with a caution warning.

   If you lose the secret, click *Regenerate client secret*. Your old secret stops working immediately, so update it in your system right away.

   Screenshot: "Regenerated credentials" dialog showing a success message ("Client secret successfully regenerated") and a table with Name, Client ID, and Secret fields displayed. A warning says this is the only time the secret will be visible.

**NOTE**

If you integrated earlier and are using keys from a *Recurring donations* sales unit,
use your [sales unit API keys](https://developer.vippsmobilepay.com/docs/knowledge-base/api-keys.md#what-are-api-keys) with
[standard authentication](https://developer.vippsmobilepay.com/docs/APIs/access-token-api/standard-authentication.md) instead. That is the
same flow partners use, shown in the *Partners* tab of
[Step 2 - Get an access token](https://developer.vippsmobilepay.com/docs/APIs/donations-api/quick-start.md#step-2---get-an-access-token).

You don't need separate Donations keys. Use the [partner keys](https://developer.vippsmobilepay.com/docs/partner/partner-keys.md#partner-keys)
you already have -- one set works across all the merchants you manage.

If you don't have partner keys yet, see
[How to get API keys](https://developer.vippsmobilepay.com/docs/partner/partner-keys.md#how-to-get-api-keys).

Unlike merchant-level keys, partner keys use
[standard authentication](https://developer.vippsmobilepay.com/docs/APIs/access-token-api/standard-authentication.md).
See [Step 2 - Get an access token](https://developer.vippsmobilepay.com/docs/APIs/donations-api/quick-start.md#step-2---get-an-access-token) for an example request.

You only get data for the donations sales units you have been granted access to -- see
[Partner-specific behavior](#partner-specific-behavior).

## Endpoints

Include the access token in the `Authorization` header of each request.

The following endpoints are available:

| Endpoint                                                           | Description                     |
| ------------------------------------------------------------------ | ------------------------------- |
| [`GET:/donations/v1/reports/payments`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml)| Get a list of all single and recurring donations made to a merchant in a given interval |
| [`GET:/donations/v1/agreements/{agreementId}`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml)| Get detailed information about a specific agreement |
| [`POST:/donations/v1/agreements/{agreementId}/stop`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml) | Stop an agreement |

### Get a list of donation payments

Use [`GET:/donations/v1/reports/payments`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml) to retrieve all your donation payments as an array of payment objects.

**NOTE**

#### Partner-specific behavior

When calling this endpoint as a partner:

- The response only includes payments for donations sales units the partner has been granted access to.
- If `recipientHandles` is included, every handle must be both valid and accessible for that partner.
- If one or more requested `recipientHandles` are not accessible (or not found), the endpoint returns `403 Forbidden`.

Send [`GET:/donations/v1/reports/payments`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml) with your access token and `from`/`to` query parameters to specify the time interval.

For example:

```bash
curl -X GET https://api.vipps.no/donations/v1/reports/payments?from=2025-10-08T06:01:09.1234567Z&to=2030-06-30T23:59:59.9999999Z
-H "Authorization: Bearer YOUR-ACCESS-TOKEN"
```

A successful response includes the date range and a `payments` array, where each entry contains `payer`, `amount`, `currency`, and capture time.

For example:

```json
{
  "from": "2025-10-24T14:15:22Z",
  "to": "2025-10-24T14:15:22Z",
  "payments": [
    {
      "externalReference": "spring-promotion-2025",
      "agreementId": "79458f91-82b5-4c38-a886-56df6a6b7980",
      "message": "string",
      "payer": {
        "name": "Ada Lovelace",
        "phoneNumber": "4712345678"
      },
      "capturedAt": "2025-10-24T14:15:22Z",
      "pspReference": "11268125611",
      "transactionReference": "11268125611",
      "recipientHandle": "api:922061",
      "amount": "50001",
      "currency": "NOK"
    }
  ]
}
```

## Using the Report API

Merchants can also use the [Report API](https://developer.vippsmobilepay.com/docs/APIs/report-api/README.md) with the same merchant-level keys to retrieve settlement and ledger data alongside their donations data.

See [Authenticating to the Report API](https://developer.vippsmobilepay.com/docs/APIs/report-api/api-guide/overview.md) for details.

## Payments report best practices

The payments report endpoint (`GET:/donations/v1/reports/payments`) uses timestamp-based batching for efficient data retrieval.

### Batching

#### Key concepts

- **Data update frequency**: There is no need to poll for new data more often than once a minute.
- **Payload Size Limits**: The API has built-in limits on response payload size for performance reasons
- **No Guarantee of Complete Intervals**: You are not guaranteed to receive all payments within a given time interval in a single request
- **Timestamp-Based Pagination**: Use the latest timestamp from the previous response as the `from` parameter for the next request
- **Dynamic Payload Size**: The number of payment entries returned in each response may vary and is subject to change. Do not implement logic that depends on a specific number of payments per response.

#### Recommended implementation

1. **Start with your desired time range**: Set both `from` and `to` parameters for your initial request
2. **Process the response**: Handle all payments returned in the response
3. **Check for more data**: If the response contains payments, use the latest `capturedAt` timestamp as the new `from` parameter
4. **Continue pagination**: Make subsequent requests with the updated `from` parameter until you don't receive any new payments in the payload

#### Important considerations

- **Timestamp Precision**: Always use the exact `capturedAt` timestamp from the response to avoid missing payments
- **Duplicate Handling**: Implement logic to handle duplicate payments that may appear across different payloads. The last payment of the previous payload will be included if using the exact timestamp.
- **Empty Responses**: An empty `payments` array indicates no more data is available for the given time range

## Webhooks integration

Receive real-time notifications when donation agreements are started, stopped, or changed. Register your webhook URL as described in the [Webhooks API guide](https://developer.vippsmobilepay.com/docs/APIs/webhooks-api/api-guide.md).

**For partners**

Partners can register `donations.*` webhooks using their partner-level API keys.
A partner-level registration without a Merchant Serial Number (MSN) covers donations events for all sales units connected to the partner, including sales units added in the future.
See [Partner webhooks](https://developer.vippsmobilepay.com/docs/APIs/webhooks-api/api-guide.md#partner-and-psp-webhooks) for details.

### Agreement webhook events

Webhook event types for donation agreements:

| Event type | Description |
|------------|-------------|
| `donations.agreement.started.v1` | Donation agreement has been started |
| `donations.agreement.stopped.v1` | Donation agreement has been stopped |
| `donations.agreement.withdrawal-day-changed.v1` | Donation agreement withdrawal day has been changed |
| `donations.agreement.amount-changed.v1` | Donation agreement amount has been changed |

### Create a webhook

Register your webhook endpoint to receive notifications about agreement events:

```bash
curl -X POST https://api.vipps.no/webhooks/v1/webhooks \
-H "Authorization: Bearer YOUR-ACCESS-TOKEN" \
-H "Content-Type: application/json" \
--data '{
    "url": "YOUR-CALLBACK-URL",
    "events": ["donations.agreement.started.v1"]
}'
```

A successful response confirms the registration:

```json
{
   "id":"497f6eca-6276-4993-bfeb-53cbbbba6f08",
   "secret":"090a478d-37ff-4e77-970e-d457aeb26a3a"
}
```

### Agreement webhook payloads

#### Started event payload

When a donation agreement is started, you will receive the following payload:

| Field name | Type | Description | Example |
|------------|------|-------------|---------|
| `agreementId` | string | ID of the donation agreement | `2518f497-bfad-43a6-8914-fd0168a6c221` |
| `startedAt` | ISO 8601 UTC date | When the agreement was started | `2026-01-31T17:26:50.8789251+00:00` |

Example payload:

```json
{
  "agreementId": "2518f497-bfad-43a6-8914-fd0168a6c221",
  "startedAt": "2026-01-31T17:26:50.8789251+00:00"
}
```

#### Stopped event payload

When a donation agreement is stopped, you will receive the following payload:

| Field name | Type | Description | Example |
|------------|------|-------------|---------|
| `agreementId` | string | ID of the donation agreement | `2518f497-bfad-43a6-8914-fd0168a6c221` |
| `stoppedAt` | ISO 8601 UTC date | When the agreement was stopped | `2026-01-31T17:26:50.8789251+00:00` |

Example payload:

```json
{
  "agreementId": "2518f497-bfad-43a6-8914-fd0168a6c221",
  "stoppedAt": "2026-01-31T17:26:50.8789251+00:00"
}
```

#### Withdrawal day changed event payload

When the withdrawal day of a donation agreement is changed, you will receive the following payload:

| Field name | Type | Description | Example |
|------------|------|-------------|---------|
| `agreementId` | string | ID of the donation agreement | `34580d79-0628-4ed5-bb0a-75a6f2a6fae1` |
| `changedAt` | ISO 8601 UTC date | When the withdrawal day was changed | `2026-02-15T17:00:22.1234567Z` |
| `withdrawalDay` | integer | New withdrawal day (1-28) | `12` |
| `nextPeriodKey` | string (optional) | Billing period key for the next withdrawal. Format: `YYYY-MM` (e.g. March 2026 is `2026-03`). Omitted or null when the next billing period is not yet determined (e.g. before the first schedule has been initialized). | `2026-03` |

Example payload (when next period is known):

```json
{
  "agreementId": "34580d79-0628-4ed5-bb0a-75a6f2a6fae1",
  "changedAt": "2026-02-15T17:00:22.1234567Z",
  "withdrawalDay": 12,
  "nextPeriodKey": "2026-03"
}
```

When the next billing period is not yet determined, `nextPeriodKey` may be omitted or `null`.

#### Amount changed event payload

When the amount of a donation agreement is changed, you will receive the following payload:

| Field name | Type | Description | Example |
|------------|------|-------------|---------|
| `agreementId` | string | ID of the donation agreement | `34580d79-0628-4ed5-bb0a-75a6f2a6fae1` |
| `changedAt` | ISO 8601 UTC date | When the amount was changed | `2026-02-15T17:00:22.1234567Z` |
| `amount` | object | New amount | See below |
| `amount.value` | integer | Amount in minor units (e.g. øre/cents) | `20000` |
| `amount.currency` | string | ISO 4217 currency code | `DKK` |

Example payload:

```json
{
  "agreementId": "34580d79-0628-4ed5-bb0a-75a6f2a6fae1",
  "changedAt": "2026-02-15T17:00:22.1234567Z",
  "amount": {
    "value": 20000,
    "currency": "DKK"
  }
}
```

For more details about webhooks, see the [Webhooks API guide](https://developer.vippsmobilepay.com/docs/APIs/webhooks-api/api-guide.md).

### Get agreement details

After receiving a webhook notification, retrieve full agreement details using [`GET:/donations/v1/agreements/{agreementId}`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml).

For example:

```bash
curl -X GET https://api.vipps.no/donations/v1/agreements/2518f497-bfad-43a6-8914-fd0168a6c221
-H "Authorization: Bearer YOUR-ACCESS-TOKEN"
```

The response includes payer information, schedule, and amount.

For example:

```json
{
  "id": "2518f497-bfad-43a6-8914-fd0168a6c221",
  "recipientHandle": "NO:6666",
  "startedAt": "2026-01-31T17:26:50.8789251+00:00",
  "schedule": {
    "interval": "MONTHLY",
    "withdrawalDay": 10
  },
  "amount": {
    "currency": "NOK",
    "value": 2300
  },
  "payer": {
    "firstName": "Ada",
    "lastName": "Lovelace",
    "phoneNumber": "4712345678",
    "address": {
      "country": "NO",
      "region": "Oslo",
      "postalCode": "0154",
      "addressLine1": "Robert Levins gate 5"
    },
    "email": "user@example.com",
    "emailVerified": true
  }
}
```

Response behavior:

- `200 OK` when the agreement exists and the caller has access to it.
- `404 Not Found` if the agreement does not exist or the caller does not have access to it.

For more details, see [`GET:/donations/v1/agreements/{agreementId}`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml) in the spec.

### Stop an agreement

Stop an active agreement using [`POST:/donations/v1/agreements/{agreementId}/stop`](https://developer.vippsmobilepay.com/redocusaurus/donations-swagger-id.yaml).

For example:

```bash
curl -X POST https://api.vipps.no/donations/v1/agreements/2518f497-bfad-43a6-8914-fd0168a6c221/stop \
-H "Authorization: Bearer YOUR-ACCESS-TOKEN"
```

Response behavior:

- `200 OK` when the agreement is stopped.
- `200 OK` if the agreement is already stopped (idempotent).
- `404 Not Found` if the agreement does not exist or the caller does not have access to it.

> **Full site overview:** For every page in this documentation, read [https://developer.vippsmobilepay.com/llms.txt](https://developer.vippsmobilepay.com/llms.txt).
