# Connect a calendar or mailbox from your own software

This guide describes the available API within the documented release limits. Current key, user, package and object permissions remain required. Not every website feature is available through the API. The fictional practice environment does not connect to real providers.

## Preparation

Use a production API key belonging to the correct user and an account plan that includes the connection. An administrator can limit key permissions. You need `verbindingen:beheren` to inspect, connect and disconnect accounts, and `agenda:lezen` to read events. Mailbox sending consent additionally requires `berichten:verzenden`. Existing keys do not receive these permissions automatically. Keep the key on your server.

Base URL: `https://api.rapportly.io/api/rapportly/v1`. Send `Authorization: Bearer <your API key>` with every API request. The user signs in to the provider in their browser. API responses never contain provider passwords or access tokens.

| soort | provider | scope_versie |
|---|---|---|
| agenda | google or m365 | 1 |
| mailbox | gmail or m365 | 1 for drafts, 2 for intentional sending |

Gmail uses the same native compose permission for both versions. Sending remains a separate Rapportly permission and an intentional action. Connecting never sends a message automatically.

## 1. Read the current connection

`GET /verbindingen/agenda/google`

Keep the exact returned `basis`. It is a change identifier, not a token. `gekoppeld` describes the current Rapportly connection and `beschikbaar` indicates server provider configuration. `verversing_status` may be `verwerken` (processing) or `onzeker` (uncertain). `opnieuw_toestemming_nodig: true` means a new consent request is needed. A database failure returns an error, never a misleading empty connection.

## 2. Request permission

`POST /autorisaties`, with `Content-Type: application/json` and a unique `Idempotency-Key`, such as `crm-calendar-consent-0001`.

```json
{"soort":"agenda","provider":"google","scope_versie":1,"basis":"geen","bevestigd":true}
```

Use `geen` only when step 1 returned it; otherwise copy the exact current basis. Store the request ID and idempotency key. Open the returned `url` for this user to approve access at Google or Microsoft. Requests expire after 15 minutes, with at most 5 open requests per API key. Rapportly handles the callback; do not supply your own redirect URL.

## 3. Retrieve the outcome

`GET /autorisaties/<request ID>`, using the same API key. Status values: `wacht_op_toestemming` (awaiting permission), `verwerken` (processing), `gekoppeld` (completed), `mislukt` (failed), `verlopen` (expired), `onzeker` (uncertain). Increase the delay between repeated status requests and respect limit responses.

If the start response is lost, repeat the identical body and idempotency key. A completed or expired request does not return a fresh provider URL. For an uncertain result, check the request and current connection again before making a new intentional attempt with a new idempotency key and current basis. A provider authorization code is never exchanged blindly a second time. Revoked keys or changed permissions prevent new connection storage.

A completed request is historical evidence. Repeat step 1 to check whether the connection is still active now.

## 4. Read upcoming events

`GET /agenda/afspraken?uren=24`, with `agenda:lezen`. Supply an integer from 1 to 72; the default is 24 hours. Results contain the existing Rapportly customer match, restricted to readable customers. Raw attendee email addresses are excluded. Editing calendar events is not offered by this existing calendar integration.

## 5. Disconnect intentionally

Repeat step 1. Send `DELETE /verbindingen/agenda/google`, `Content-Type: application/json`, a new `Idempotency-Key`, and:

```json
{"basis":"<exact current basis>","bevestigd":true}
```

This removes the access stored by Rapportly and cancels pending consent requests for this user/provider. Repeat the exact request after response loss. An old replay does not remove a connection created later. `status: ontkoppeld` is a receipt; read the current connection separately.

`provider_toestemming_ingetrokken: false` explicitly means this does not revoke the general permission in the Google/Microsoft account. A send already submitted to the provider cannot be undone by disconnecting locally.

## Errors and credits

After a basis conflict, read again before making an intentional new request. Wait when refresh is busy. An uncertain refresh may require new consent. Never automatically remove a new connection to repair an old error. Plan, key, scope and user permissions still apply. These five connection/calendar actions do not start AI work or book credits themselves. Later API processing uses normal personal credits and the key budget.

Complete technical testing, provider configuration verification and website publication are still pending. This draft is not proof of live availability.


## Self-service recovery and technical receipts

Under Account, Rapportly shows **Reconnect** when access has an uncertain refresh outcome. Approve access again with Google or Microsoft. If only the status request fails temporarily, choose **Check status again**; that request does not disconnect anything. Mailbox recovery preserves the previous choice of drafts or explicit sending, without sending a message automatically.

An authorization request expires after 15 minutes. Maintenance then removes its temporary claim data. A technical result reference is removed after 30 days. The minimal receipt stays with the key, so repeating the same Idempotency-Key cannot start a new authorization and an old disconnection cannot remove a newer connection. Receipts are removed when the key, organization or user account is actually deleted. Removing a member from a team is not account deletion. These rules do not delete existing reports or revoke the general Google/Microsoft grant.


## 6. Choose your default mailbox

Read `GET /mailboxvoorkeur` with `verbindingen:beheren`. The response includes the saved preference, the effective default, a `basis` for that preference and the current mailboxes. Only select a mailbox with `verzendbaar: true`. Use that mailbox's unchanged `verbinding_basis`. These values are technical versions, not provider tokens.

Changing the preference requires both `verbindingen:beheren` and `berichten:verzenden` on the key and within its administrator limit. The user must have connected this mailbox with sending consent. Send `PUT /mailboxvoorkeur`, a new `Idempotency-Key`, `Content-Type: application/json` and:

```json
{
  "provider": "gmail",
  "basis": "<basis from GET /mailboxvoorkeur, possibly geen>",
  "verbinding_basis": "<verbinding_basis of the selected mailbox>",
  "bevestigd": true
}
```

For Outlook use `m365`. You cannot specify another user, organisation, email address or provider URL. An administrator controls key permissions; the connection and preference belong to the member associated with that key.

The response contains `ontvangst` (what this request saved) and `huidig` (the current preference read again). If the response is lost, repeat exactly the same body and idempotency key. An old receipt may name Gmail while `huidig` now identifies Outlook. Replaying does not overwrite that newer preference. Display the current value from `huidig`.

For `mailvoorkeur_basis_conflict` or `mailvoorkeur_verbinding_conflict`, read again and ask the user to choose before creating a new idempotency key. Token rotation can also change the connection basis. For `mailvoorkeur_niet_gekoppeld`, restore the connection or sending consent first. For a temporary 503, repeat exactly or read the current preference. Never widen key permissions automatically.

Changing the preference sends no message and consumes no AI credits. Existing outbox requests retain their saved provider. New message requests separately follow the normal preview, approval, connection checks and sending permissions. A missing preferred mailbox never automatically switches sending to the other mailbox.

In complete API mode, the website uses the same version contract. Conflicts offer **Load current preference**. Minimal technical preference receipts remain associated with the key or account for safe replay. They contain no message content or provider tokens and cascade when the associated key, organisation or user is actually deleted. Native website receipts without an API key follow the organisation/user. The outbox retains its separate retention policy.
