# Project Orders

Use **Project Orders** to fund a specific project directly by `projectId`, without portfolio allocation. This is useful when you want to support a single project or allocate a fixed dollar amount.

## Overview

- **Offsettable projects** (`cost_per_ton`): Creates offset orders; response includes `impact.tons`
- **Non-offsettable projects** (e.g. policy, conservation): Creates project donations
- **Tree-measured projects** (`cost_per_tree`): Not supported — use `/api/tree-orders` instead

> **Tip:** To find available project IDs, browse the [Projects summary page](https://www.wren.co/projects-summary) for a human-readable list, or call [`GET /api/portfolios`](https://www.wren.co/docs/api/portfolios) — each portfolio includes a `projects` array with project `id` values.

## POST /api/project-orders

POST `/api/project-orders`

### Authentication

Required. Use a **team API token** (recommended) or legacy personal API token via Basic auth or Bearer token. Account required for personal tokens. **Test tokens** (`wren_test_…`) return canned responses without side effects — see [Test mode](https://www.wren.co/docs/api#test-mode).

### Headers

- `Content-Type: application/json` or `application/x-www-form-urlencoded`

### Request body

| Attribute | Type | Description & Constraints |
| --- | --- | --- |
| `projectId` | integer | **Required.** ID of the project to fund (> 0). |
| `amountInUsdCents` | integer | **Required.** Amount in USD cents. Minimum 100 ($1.00). |
| `note` | string | Optional. Note for the order. |
| `dryRun` | boolean | Optional. If true, no charge; returns preview only. |
| `sendReceiptEmail` | boolean | Optional. If true, sends a receipt email when `dryRun` is `false`. |
| `onBehalfOfName` | string | Optional. Name of the end-customer this order is being placed for. Shown as the purchaser on the impact certificate. Max 200 characters. |
| `onBehalfOfEmail` | string | Optional. Email of the end-customer this order is being placed for. Stored alongside the order; not used for sending email. Max 320 characters. |

### Minimum amount

`amountInUsdCents` must be at least 100 (USD cents = $1.00).

### Example requests

**JSON:**

**Form-encoded:**

**Dry run (no charge):**

### Success response

HTTP `200`

- `id` — Stripe charge ID, or `null` when `dryRun=true`
- `amountCharged` — In user currency's smallest denomination
- `impact.tons` — Included only when the project has `cost_per_ton`

### Error responses

**400 Bad Request** — Invalid payload, missing required fields, `amountInUsdCents` below minimum, project ineligible, or tree-measured project (use `/api/tree-orders`).

**403 Forbidden** — Missing/invalid auth or not an account user.
