---
title: Create an offer (POST /api/v2/offers) | HelpRange API
description: POST /api/v2/offers: Creates an offer with its own link: based on a folder (folder_id – new files show up), from documents (file_ids), or empty with just a title and client.
url: https://www.helprange.com/developers/api/create-offer
---

POST

# Create an offer

`https://www.helprange.com/api/v2/offers`

Creates an offer with its own link: based on a folder (folder_id – new files show up), from documents (file_ids), or empty with just a title and client. Offers without a folder get their own folder "Offer - <title>". The API never e-mails the client: send the returned url yourself.

**Plans:** Max, Unlimited, Deal Room Pass, trial. **Auth:** `Authorization: Bearer hr_live_…` (team key), `X-API-Key`, `Authorization: Api-Key <key>` or an OAuth `Bearer` token. **Scope:** `links:write`. **Operation id:** `createOffer`

## Request body

Content types: `application/json`, `application/x-www-form-urlencoded`.

| Field | Type | Description |
|---|---|---|
| `folder_id` | integer | Base the offer on this folder. |
| `file_ids` | array of integer | Documents (a JSON list, repeated form fields or "1,2"). |
| `status` | "active" / "draft" | Default active. |
| `title` | string | What the client sees as the title. Create: default the folder's / first document's name. |
| `client_first_name` | string |  |
| `client_last_name` | string |  |
| `client_company` | string |  |
| `client_email` | string | The client's e-mail – never e-mailed by the API. |
| `message` | string | Message on the offer page. (max length 2000) |
| `price_summary` | string | One line, e.g. "3 packages, from 2,400 EUR". |
| `show_accept` | boolean | "Accept offer" button (default on). |
| `accept_label` | string |  |
| `show_contact` | boolean | "Request contact" button (default on). |
| `contact_label` | string |  |
| `show_decline` | boolean | "Decline" button with an optional reason (default off). |
| `decline_label` | string |  |
| `require_email_verification` | boolean | The client verifies their e-mail with a one-time code (default on). |
| `access` | "any" / "email" / "domain" | With e-mail verification: anyone, only client_email, or client_email and colleagues at the same domain. |
| `allow_download` | boolean |  |
| `watermark` | boolean |  |
| `expires_on` | string | Last day, YYYY-MM-DD ("" removes it). |
| `passcode` | string | Asked before the offer opens ("" removes it). |
| `screenshot_protection` | boolean | Pro and higher (else 402). |
| `one_viewer_at_a_time` | boolean |  |
| `open_directly` | boolean | One-file offers: open the document directly instead of the offer page. |
| `layout` | "classic" / "split" / "cover" / "minimal" |  |

## Example request

```
curl -X POST https://www.helprange.com/api/v2/offers \
  -H "X-API-Key: $HELPRANGE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary '{"title": "Fit-out Q1", "file_ids": [250, 251], "client_company": "Acme", "client_email": "anna@acme.com", "access": "domain", "show_decline": true, "passcode": "oak-41", "expires_on": "2026-12-31"}'
```

```
const res = await fetch('https://www.helprange.com/api/v2/offers', {
  method: 'POST',
  headers: {'X-API-Key': process.env.HELPRANGE_API_KEY, 'Content-Type': 'application/json'},
  body: JSON.stringify({
    "title": "Fit-out Q1",
    "file_ids": [
      250,
      251
    ],
    "client_company": "Acme",
    "client_email": "anna@acme.com",
    "access": "domain",
    "show_decline": true,
    "passcode": "oak-41",
    "expires_on": "2026-12-31"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status}: ${data.error || data.message || data.reason}`);
console.log(data);
```

```
import os

import requests

r = requests.post(
    'https://www.helprange.com/api/v2/offers',
    headers={'X-API-Key': os.environ['HELPRANGE_API_KEY']},
    json={
        "title": "Fit-out Q1",
        "file_ids": [250, 251],
        "client_company": "Acme",
        "client_email": "anna@acme.com",
        "access": "domain",
        "show_decline": True,
        "passcode": "oak-41",
        "expires_on": "2026-12-31",
    },
    timeout=60,
)
r.raise_for_status()
print(r.json())
```

The samples read the key from the `HELPRANGE_API_KEY` environment variable.

## Responses

| Status | Description |
|---|---|
| `201` | Created |
| `400` | Invalid input – the message says which parameter. |
| `401` | Missing or invalid API key / OAuth token. Team keys: code invalid_key, key_revoked, key_expired or key_owner_removed. |
| `402` | Your plan does not include the REST API (or this feature). |
| `403` | The team API key lacks the scope this endpoint needs. |
| `404` | Not found – or not yours (the API never says which). |
| `405` | Wrong HTTP method for this endpoint. |
| `429` | A usage limit was reached – wait Retry-After seconds. |

Example response · 201

```
{
  "id": 31,
  "title": "Fit-out Q1",
  "status": "active",
  "expired": false,
  "client": {
    "first_name": "Anna",
    "last_name": "Nowak",
    "company": "Acme",
    "email": "anna@acme.com"
  },
  "kind": "files",
  "url": "https://www.helprange.com/o/Xk2pQ9/",
  "document_views": 4,
  "page_visits": 2,
  "last_viewed_at": "2026-11-11T09:12:00+00:00",
  "sent_at": null,
  "created_at": "2026-11-11T08:00:00+00:00",
  "updated_at": "2026-11-11T08:00:00+00:00",
  "stored_status": "active",
  "public_url": "https://www.helprange.com/o/Xk2pQ9/",
  "panel_url": "https://www.helprange.com/user/offers/31/",
  "message": "Hi Anna, here is our proposal.",
  "price_summary": "from 2,400 EUR",
  "buttons": {
    "accept": {
      "shown": true,
      "label": ""
    },
    "contact": {
      "shown": true,
      "label": ""
    },
    "decline": {
      "shown": true,
      "label": ""
    }
  },
  "protection": {
    "require_email_verification": true,
    "access": "domain",
    "allowed_emails": "anna@acme.com @acme.com",
    "allow_download": false,
    "watermark": false,
    "passcode": true,
    "screenshot_protection": false,
    "one_viewer_at_a_time": false,
    "expires_on": "2026-12-31"
  },
  "open_directly": false,
  "layout": "classic",
  "theme": "light",
  "base_folder": null,
  "own_folder": {
    "id": 77,
    "name": "Offer - Fit-out Q1"
  },
  "files": [
    {
      "id": 250,
      "name": "proposal.pdf",
      "folder_id": 77,
      "source": "own_folder",
      "view_url": "https://www.helprange.com/view/5b0c.../proposal.pdf",
      "views": 3
    }
  ],
  "people": 1,
  "engagement": 82,
  "responses_count": 1,
  "responses": [
    {
      "kind": "declined the offer",
      "type": "decline",
      "offer_id": 31,
      "email": "anna@acme.com",
      "email_verified": true,
      "offer": "Fit-out Q1",
      "comment": "Too expensive",
      "document_id": null,
      "engagement": 64,
      "country": "PL",
      "at": "2026-11-11T10:00:00+00:00"
    }
  ],
  "sent_to": null,
  "created_by": "ann@acme.com",
  "legacy_url": null,
  "send_by_email": "HelpRange does not e-mail offers through the API or MCP. Send the offer link (url) yourself, or use \"Send by e-mail\" on the offer page in HelpRange."
}
```

## Try it

**Uses your real account.** The request goes from your browser straight to `www.helprange.com` with your API key and acts as you – this POST **changes data** and may e-mail people. The key stays in this page (in this tab's session storage only if you tick the box), is never put in a URL and is not sent to analytics. Do not paste a key on a shared computer.
 API key

  Remember in this tab   JSON body { "title": "Fit-out Q1", "file_ids": [ 250, 251 ], "client_company": "Acme", "client_email": "anna@acme.com", "access": "domain", "show_decline": true, "passcode": "oak-41", "expires_on": "2026-12-31" }

```

```
