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

# PickFu API v2

> Overview of the PickFu v2 REST API: endpoints for surveys, media, traits, billing, results, and webhooks, plus how v2 differs from v1.

The PickFu **v2 API** is a greenfield surface mounted at `https://api.pickfu.com/v2`, alongside the existing v0/v1 API. It is designed for partners integrating PickFu into their own products — drafting a survey, funding it, publishing it, and reading the results — end-to-end, without ever loading `app.pickfu.com`.

v2 keeps the same team, same account, same billing, and the same pricing as the PickFu app. It is a new *contract*, not a new product.

<Note>
  If you're already using v1 (`/v1`), you don't need to switch. v0, v1, and v2 run side-by-side on the same production API. Pick v2 when you want the ergonomics below; stay on v1 if it's already working for you.
</Note>

## Base URLs

```
https://api.pickfu.com/v2
```

The machine-readable OpenAPI 3.1 contract is served unauthenticated at `GET /v2/openapi.json`. Point client generators (Stripe-style SDKs, Postman, `openapi-typescript`) at that URL.

## What's in v2

<CardGroup cols={2}>
  <Card title="Me" icon="user">
    `GET /v2/me` — the calling key, its scopes, and the team it acts for.
  </Card>

  <Card title="Surveys" icon="clipboard-list">
    Draft, edit, read, list, and stop surveys. Every read includes a `cost` quote.
  </Card>

  <Card title="Media" icon="image">
    `POST /v2/media` — host images and videos on the PickFu CDN.
  </Card>

  <Card title="Traits" icon="users">
    `GET /v2/traits` — audience traits available per respondent country.
  </Card>

  <Card title="Billing" icon="credit-card">
    Credit balance, credit packs bought on Stripe Checkout, saved cards via the Stripe Billing Portal.
  </Card>

  <Card title="Publish + pay" icon="rocket">
    `POST /v2/surveys/{id}/publish` — one call that pays for and publishes a draft.
  </Card>

  <Card title="Results" icon="chart-bar">
    Cursor-paged responses and a synchronous CSV export.
  </Card>

  <Card title="Webhooks" icon="webhook">
    Signed `survey.completed` and `order.paid` deliveries.
  </Card>
</CardGroup>

## How v2 differs from v1

<Note>
  v2 is a **different resource shape** from v1. It is not a drop-in upgrade — resource IDs, error envelopes, and pagination shapes are all different by design. Choose one surface per integration.
</Note>

### Canonical PickFu IDs

Every v2 resource identifies itself with a canonical, prefixed **PickFu ID**:

| Prefix | Resource |
| - | - |
| `tm_` | Team |
| `usr_` | User |
| `srv_` | Survey |
| `qst_` | Question |
| `opt_` | Option |
| `rsp_` | Response |
| `ord_` | Order (survey or credit pack) |
| `whk_` | Webhook endpoint |
| `evt_` | Webhook event |

v2 never accepts or emits legacy GUIDs as resource IDs. The browser results page URL is unchanged and continues to use the survey's GUID; that's a browser URL, not a v2 identifier.

### Scoped API keys

v2 accepts **API keys only** (`sk_live_…`). OAuth tokens are v1-only.

Keys carry explicit **scopes**: `read`, `write`, and/or `spend`. A key with no scopes is rejected with `403 api_key_unscoped` — there is no implicit "god mode" any more. See [Authentication](/docs/api-reference/v2/authentication).

### Stripe-shaped error envelope

Every non-2xx response — validation, `404`, `429`, unknown route — uses the same envelope:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_missing",
    "message": "questions is required",
    "param": "questions"
  },
  "requestId": "req_01J9C2VZH8..."
}
```

`requestId` is also returned as `X-Request-Id`. Quote it when you file a support ticket. See [Errors](/docs/api-reference/v2/errors).

### Cursor pagination

List endpoints return `{ data, hasMore, nextCursor }`. There are no offsets and no totals. Pass `nextCursor` back as `?cursor=…` to fetch the next page. See [Pagination](/docs/api-reference/v2/pagination).

### Idempotency

`POST /v2/orders` and `POST /v2/surveys/{id}/publish` **require** an `Idempotency-Key` header. Retrying with the same key and body replays the original 2xx response for 24 hours. See [Idempotency](/docs/api-reference/v2/idempotency).

### Webhook signing

Every delivery is a `{ id, type, createdAt, data: { object } }` envelope signed with `X-PickFu-Signature: t=<unix-seconds>,v1=<hex-hmac>`. See [Webhooks](/docs/api-reference/v2/webhooks).

## The publish flow

The single interesting workflow in v2 is **draft → quote → publish → results**. Everything else supports it.

<Steps>
  <Step title="Create a draft">
    `POST /v2/surveys` returns a draft survey (`status: "unpublished"`) with a `cost` quote and the team's current `creditBalance`. Nothing is charged yet.
  </Step>

  <Step title="Read or refresh the quote">
    `GET /v2/surveys/{id}` and `PATCH /v2/surveys/{id}` both return a fresh `cost` quote. The most recent quote is what publish will honour.
  </Step>

  <Step title="Publish">
    `POST /v2/surveys/{id}/publish` charges the quote — credits first (oldest expiry first), then any shortfall to the team's default saved card. `200` means **paid**, not yet live.

    If the quote has changed since your last read, publish answers `409 quote_changed` and doesn't charge anything. If there's a shortfall and no saved card, it answers `402 insufficient_credits` with the smallest pack that would cover it.
  </Step>

  <Step title="Wait for completion">
    Poll `GET /v2/surveys/{id}` (`status` moves `in-progress` → `completed`) or listen for the `survey.completed` webhook. Then read `GET /v2/surveys/{id}/responses` or download `GET /v2/surveys/{id}/exports/csv`.
  </Step>
</Steps>

The [publishing and payments](/docs/api-reference/v2/payments) page walks through funding, `402` recovery, and the Stripe Billing Portal.

## Next steps

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/docs/api-reference/v2/authentication">
    Mint a key, choose scopes, and identify your team.
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/docs/api-reference/v2/errors">
    The `{ error, requestId }` envelope and per-status guidance.
  </Card>

  <Card title="Rate limits" icon="gauge" href="/docs/api-reference/v2/rate-limits">
    Per-team limits and how to back off on `429`.
  </Card>

  <Card title="Pagination" icon="list" href="/docs/api-reference/v2/pagination">
    Cursor pagination for every list endpoint.
  </Card>

  <Card title="Idempotency" icon="rotate" href="/docs/api-reference/v2/idempotency">
    Safe retries for order creation and publish.
  </Card>

  <Card title="Publishing and payments" icon="credit-card" href="/docs/api-reference/v2/payments">
    Quotes, credits, saved cards, credit packs, and the Billing Portal.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/docs/api-reference/v2/webhooks">
    Endpoints, signing, and the `survey.completed` / `order.paid` events.
  </Card>
</CardGroup>


## Related topics

- [PickFu REST API reference and conventions](/docs/api-reference/introduction.md)
- [Authenticate the PickFu CLI, MCP server, and API](/docs/authentication.md)
- [PickFu CLI for surveys and automation](/docs/integrations/cli.md)
- [What integrations are available with PickFu?](/help/what-integrations-are-available-with-pickfu.md)
- [PickFu MCP server for Claude, Cursor, and ChatGPT](/docs/integrations/mcp-server.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.