> ## Documentation Index
> Fetch the complete documentation index at: https://developer.findity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Policies

List, upload, update, and remove expense policy documents on a Findity organization.

This guide walks through managing the policy documents attached to a customer organization. You'll list the current documents, download an existing one, update its metadata, and delete documents that are no longer in use. The active policy is surfaced back to end users through the `policyUrl` field on the organization.

## Overview

A **policy document** is a PDF (or other file) that describes the expense rules for an organization: what employees can claim, receipt requirements, mileage rates, per-diem limits, and so on. Each organization can hold one or more policy documents, and Findity exposes a pre-signed URL to the active document on the organization record so end users can read it in the app.

The typical lifecycle is: (1) list existing documents, (2) fetch a specific document to review it, (3) update its display metadata, and (4) delete documents that have been superseded.

Every policy document has two parts:

* A **binary file** — the PDF itself, stored by Findity and served over a pre-signed URL.
* A **metadata record** — the display name, filename, upload timestamp, and uploader. Returned by the list endpoint and editable via `PUT`.

Because the active policy appears on the organization payload, keeping the metadata accurate (a clear `name`, the right `fileName`) is what your users will see when they open the policy from the expense app.

## Prerequisites

1. Complete [Authentication](/docs/accessing) and obtain an admin-scoped access token.
2. Create or identify the customer organization (see [Admin API — Organizations](/docs/admin-api-organizations)) and have its `organizationId` (UUID) ready. The policy endpoints use the internal UUID, not `externalId`.
3. Have the policy PDF ready if you're going to reference it in a fresh upload, along with the `documentId` of any existing document you need to update or delete.

## Key concepts

| Concept | Description |
| - | - |
| **Policy document** | A file (typically PDF) describing the organization's expense rules. Multiple documents can exist per organization. |
| **`organizationId`** | The internal UUID of the organization the policy belongs to. Different from `externalId`. |
| **`documentId`** | The internal UUID of a single policy document. Returned by the list endpoint and used on all per-document operations. |
| **`policyUrl`** | Pre-signed URL to the organization's active policy document, returned on the organization payload. Null when no policy is configured. |
| **`name`** | Display name shown to users (e.g. "Expense policy 2026"). Editable via `PUT`. |
| **`fileName`** | Original file name (e.g. `policy.pdf`). Editable via `PUT`. |

## API endpoints

All policy endpoints use the Admin API base URL. Examples in this guide use the **stage** environment — switch to the production host (`https://expense.findity.com/api/admin`) only when you're ready to go live.

```text theme={"system"}
https://stage-expense.findity.com/api/admin
```

| Operation | Method | Endpoint |
| - | - | - |
| List policy documents | `GET` | `/organizations/{organizationId}/policies/documents` |
| Get policy document (binary) | `GET` | `/organizations/{organizationId}/policies/documents/{documentId}` |
| Update policy document metadata | `PUT` | `/organizations/{organizationId}/policies/documents/{documentId}` |
| Delete policy document | `DELETE` | `/organizations/{organizationId}/policies/documents/{documentId}` |

### Required headers

Include these on every request:

| Header | Value |
| - | - |
| `Content-Type` | `application/json` |
| `Authorization` | `Bearer {access_token}` |
| `X-Findity-ApiVersion` | `3` |

<Note>
  The `GET` for a single document returns `application/pdf` (binary), not JSON. Save the response to a file or stream it — don't try to parse it as JSON.
</Note>

## Step 1 — List policy documents

Fetch every policy document currently attached to the organization. Use the results to find the `documentId` you need for the per-document operations.

`GET /organizations/{organizationId}/policies/documents`

### Query parameters

| Parameter | Type | Default | Description |
| - | - | - | - |
| `sort` | array of strings | — | Sort order. Allowed values: `fileName`, `name`, `date`, `uploadedBy`. Repeat the parameter for multi-key sorts. |

```sh cURL theme={"system"}
curl -X GET \
  "https://stage-expense.findity.com/api/admin/organizations/05b8daba9ba14a49846fe77883248cf0/policies/documents?sort=date" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Findity-ApiVersion: 3"
```

**Example response**

```json JSON theme={"system"}
{
  "data": [
    {
      "name": "Expense policy",
      "fileName": "policy.pdf",
      "date": "2024-10-21T19:32:36Z",
      "documentId": "22adfe2a080040e3892ffb89c21ec445",
      "uploadedBy": "Test User"
    }
  ]
}
```

The `documentId` returned here is what you'll pass to the `GET`, `PUT`, and `DELETE` endpoints below.

## Step 2 — Download a policy document

Fetch the binary content of a single policy document. The response is the raw file (typically `application/pdf`), not a JSON envelope.

`GET /organizations/{organizationId}/policies/documents/{documentId}`

```sh cURL theme={"system"}
curl -X GET \
  "https://stage-expense.findity.com/api/admin/organizations/05b8daba9ba14a49846fe77883248cf0/policies/documents/22adfe2a080040e3892ffb89c21ec445" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Findity-ApiVersion: 3" \
  --output policy.pdf
```

The `--output policy.pdf` flag writes the response body to a local file. Without it, cURL prints the binary to your terminal.

**Not found response**

```json JSON theme={"system"}
{
  "result": "error",
  "description": "Policy document not found"
}
```

Returned as `404` when the `documentId` doesn't match a document on the organization, or when the caller doesn't have admin scope for the organization (the API returns `404` rather than `403` in that case to avoid leaking existence).

## Step 3 — Update policy document metadata

Change the display `name` or `fileName` of an existing document. The `PUT` updates metadata only; it doesn't replace the underlying binary. To replace the file itself, delete the old document and upload a fresh one.

`PUT /organizations/{organizationId}/policies/documents/{documentId}`

### Request body — fields

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Recommended | Display name shown to users (e.g. "Expense policy 2026"). |
| `fileName` | string | Recommended | Original file name (e.g. `policy.pdf`). Shown alongside the download link. |

```sh cURL theme={"system"}
curl -X PUT \
  "https://stage-expense.findity.com/api/admin/organizations/05b8daba9ba14a49846fe77883248cf0/policies/documents/22adfe2a080040e3892ffb89c21ec445" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Findity-ApiVersion: 3" \
  -d '{
    "name": "Expense policy 2026",
    "fileName": "expense-policy-2026.pdf"
  }'
```

**Example response**

```json JSON theme={"system"}
{
  "id": "22adfe2a080040e3892ffb89c21ec445",
  "name": "Expense policy 2026",
  "created": "2024-10-21T19:32:36Z",
  "description": "",
  "mimeType": "application/pdf",
  "remoteStorageId": "s3://findity-policies/...",
  "isPublic": false,
  "signature": "b474357d403aad430dcd56f6f37342d3",
  "ownerId": "05b8daba9ba14a49846fe77883248cf0"
}
```

The response returns the full document record, including internal storage metadata. Only `name` and `fileName` are user-editable — the rest is managed by Findity.

## Step 4 — Delete a policy document

Remove a policy document from the organization. This deletes both the binary and its metadata record. If the deleted document was the organization's active policy, `policyUrl` on the organization payload becomes `null` until another document is uploaded.

`DELETE /organizations/{organizationId}/policies/documents/{documentId}`

```sh cURL theme={"system"}
curl -X DELETE \
  "https://stage-expense.findity.com/api/admin/organizations/05b8daba9ba14a49846fe77883248cf0/policies/documents/22adfe2a080040e3892ffb89c21ec445" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Findity-ApiVersion: 3"
```

A successful delete returns `200 OK` with an empty body.

<Warning>
  Delete is immediate and irreversible. The binary is removed from storage and cannot be recovered — keep a local copy if you may need to restore the document later.
</Warning>

## Reading the active policy from the organization payload

The organization record exposes the currently active policy through the `policyUrl` field:

```json JSON theme={"system"}
{
  "id": "05b8daba9ba14a49846fe77883248cf0",
  "name": "Acme AB",
  "policyUrl": "https://stage-expense.findity.com/api/v1/expense/me/organizations/05b8daba.../policies/documents/22adfe2a...?X-Findity-Expires=..."
}
```

Behavior:

* **Pre-signed URL.** The link is short-lived. Fetch a fresh organization payload when the URL expires rather than caching it long-term.
* **Null when no policy exists.** `policyUrl` is `null` on organizations with no policy documents configured.
* **Points to the active document.** When multiple policy documents exist, `policyUrl` points to the active one. Use the list endpoint above to see every document on the organization.

## Common integration patterns

**Publishing a new annual policy.** When you roll out an updated policy each year, upload the new PDF through the Findity admin UI, then use `PUT` to set a clear `name` (e.g. "Expense policy 2026") so users can distinguish it from the previous year's version. Delete the superseded document once the new one is live.

**Auditing what's attached.** Run the list endpoint periodically and check the `date` and `uploadedBy` fields to confirm no unexpected documents were added. Sort by `date` to spot the most recent uploads first.

**Cleaning up stale documents.** If an organization has accumulated old policies from prior years, iterate the list response, download each with the binary `GET` endpoint to archive it locally, then `DELETE` the ones you no longer need to keep active.

## Error handling

Findity returns a JSON envelope on errors:

```json JSON theme={"system"}
{ "result": "error", "description": "<human-readable message>" }
```

| Status | Description |
| - | - |
| `400` | Invalid JSON body on the `PUT`, or a malformed `organizationId` / `documentId`. Check the UUID format and the request body shape. |
| `401` | Access token is missing, expired, or invalid. Refresh the token and retry. |
| `403` | The token does not have admin scope for this organization. Verify the API client has the right permissions. |
| `404` | The organization or policy document isn't found — or the caller doesn't have admin scope for the organization. Confirm `{organizationId}` and `{documentId}` are correct. |
| `429` | Rate limit exceeded. Apply exponential backoff before retrying. |
| `500` | Server error. Safe to retry with backoff; if the error persists, contact support with the response body and the request `X-Request-ID` if you have one. |

## Next steps

<Cards columns={2}>
  <Card title="Organizations" href="/docs/admin-api-organizations" icon="fa-building">
    Provision and configure the organizations that hold your policy documents.
  </Card>

  <Card title="Users" href="/docs/admin-api-users" icon="fa-users">
    Add, update, and remove the employees the policy applies to.
  </Card>

  <Card title="Dimensions" href="/docs/admin-api-dimensions" icon="fa-tags">
    Configure custom dimensions and list values on an organization.
  </Card>

  <Card title="Charts of accounts" href="/docs/admin-api-charts-of-accounts" icon="fa-book">
    Manage the accounting numbers expenses are booked against.
  </Card>
</Cards>
