---
name: passionfroot
description: Use when building integrations with the Passionfroot creator
  collaboration platform. Reach for this skill when working with Partner API
  (for brands managing creator collaborations) or Creator API (for creators
  managing partnerships), handling authentication, managing conversations,
  proposals, placements, and collaborations.
metadata:
  mintlify-proj: passionfroot
  version: "1.0"
---

# Passionfroot API Skill

## Product summary

Passionfroot is a REST API for managing creator collaborations. The platform offers two API surfaces: **Partner API** (`/api/v1`) for brands managing creators and collaborations, and **Creator API** (`/api/creators/v1`) for creators managing partnerships. All requests require Bearer token authentication with an API key created in Settings → API. The API uses cursor pagination, enforces rate limits (2 req/sec per key, 20 req/sec per IP), and supports idempotency on write operations. Primary documentation: https://docs.passionfroot.me

## When to use

Use this skill when:
- Building integrations to automate creator outreach (send inquiries, manage conversations)
- Syncing collaboration data (list placements, collaborations, conversations)
- Automating proposal workflows (create, counter, accept, reject proposals)
- Managing creator catalogs and package requests
- Polling for updates to collaborations or placements using timestamp filters
- Handling API errors and implementing retry logic with idempotency keys

## Quick reference

### API endpoints by resource

| Resource | Partner API | Creator API |
|----------|-------------|------------|
| Creators | `GET /creators`, `GET /creators/{id}` | N/A |
| Partners | N/A | `GET /partners`, `GET /partners/{id}` |
| Placements | `GET /placements` | `GET /placements` |
| Collaborations | `GET /collaborations/{id}` | `GET /collaborations/{id}` |
| Conversations | `GET /conversations`, `POST /conversations/{id}/messages` | `GET /conversations`, `POST /conversations/{id}/messages` |
| Inquiries | `POST /inquiries` | N/A |
| Proposals | `POST /proposals/{id}/accept`, `POST /proposals/{id}/reject` | `POST /proposals`, `POST /proposals/{id}/counter` |
| Requests | N/A | `POST /requests/{id}/accept`, `POST /requests/{id}/decline` |

### Authentication header
```
Authorization: Bearer YOUR_API_KEY
```

### Rate limits
- **Per key**: 2 requests/second
- **Per IP**: 20 requests/second (separate buckets for Partner and Creator APIs)
- Response includes `RateLimit` header: `limit=2, remaining=1, reset=1`
- On 429: wait for `Retry-After` header, add jitter for shared keys

### Pagination
- Use opaque cursor pagination: pass `limit` (default 50, max 250), receive `nextCursor` and `hasMore`
- For incremental sync: combine with timestamp filters (`updatedAfter`, `createdAfter`, `metricsUpdatedAfter`)
- Keep filter fixed while walking all pages in a polling window

### Idempotency
- Supported on: Partner messages, inquiries; Creator messages, proposals, counter-proposals
- Header: `Idempotency-Key: <UUID v4>` (1–255 chars, scoped to account + endpoint path, retained 24h)
- Same key + body → returns stored response with `Idempotency-Replayed: true`
- Same key + different body → 422 error

### Error structure
```json
{
  "error": {
    "code": "INVALID_QUERY_PARAMETER",
    "message": "What went wrong and what to do next",
    "details": [{ "field": "limit", "message": "..." }]
  }
}
```

## Decision guidance

| Scenario | Use Partner API | Use Creator API |
|----------|-----------------|-----------------|
| Sending outreach to creators | ✓ `POST /inquiries` | ✗ |
| Listing creators you work with | ✓ `GET /creators` | ✗ |
| Listing your own placements | ✗ | ✓ `GET /placements` |
| Accepting a brand's proposal | ✗ | ✓ `POST /proposals/{id}/accept` |
| Accepting a creator's proposal | ✓ `POST /proposals/{id}/accept` | ✗ |
| Creating a counter-proposal | ✗ | ✓ `POST /proposals/{id}/counter` |
| Viewing your catalog | ✗ | ✓ `GET /products`, `GET /packages` |
| Sending a message | ✓ or ✓ | Marks read for your org/account |

| Retry strategy | When | How |
|---|---|---|
| Idempotent retry | Write operation with timeout or 5xx | Reuse same `Idempotency-Key` and body |
| Read-before-retry | Write without idempotency key | Read affected resource to check state before retrying |
| Backoff on 429 | Rate limited | Wait for `Retry-After`, add jitter if many workers share key |
| Backoff on 503 | Key verification unavailable | Retry with backoff; key itself is valid |

## Workflow

### 1. Authenticate and test
1. Create API key in Settings → API (shown once only; store in secret manager)
2. Choose endpoint: `/api/v1` (Partner) or `/api/creators/v1` (Creator)
3. Make test request: `GET /placements?limit=10` with `Authorization: Bearer $KEY`
4. Verify response contains `data` array and `pagination` object

### 2. List and filter resources
1. Start with small `limit` (10–50) to test pagination
2. Use query filters: `labelIds`, `collaborationId`, `status`, `updatedAfter`, `q` (search)
3. Follow `pagination.nextCursor` until `hasMore` is `false`
4. For incremental sync: store last `updatedAfter` timestamp, keep it fixed across pages

### 3. Send outreach (Partner API only)
1. List creators: `GET /creators?limit=50`
2. For each creator, send inquiry: `POST /inquiries` with `creatorId`, `text`, optional `campaignId`
3. Use `Idempotency-Key` (UUID v4) to retry safely
4. Response includes `conversationId`, `messageId`, `collaborationId`

### 4. Manage conversations
1. List conversations: `GET /conversations?limit=50`
2. Filter by `partnerId` (Partner) or `creatorId` (Creator), `isUnread`, `updatedAfter`
3. Send message: `POST /conversations/{id}/messages` with `text` (plain text or basic HTML)
4. Use `Idempotency-Key` for safe retries

### 5. Handle proposals
**Partner workflow:**
1. List collaborations: `GET /collaborations/{id}`
2. Accept creator proposal: `POST /proposals/{id}/accept` (naturally idempotent)
3. Reject: `POST /proposals/{id}/reject` with optional `comment`

**Creator workflow:**
1. Create proposal: `POST /proposals` with `placements`, `basePriceCents`, optional `packageId`, `name`, `comment`
2. Counter proposal: `POST /proposals/{id}/counter` (cancels pending, replaces with new)
3. Accept brand proposal: `POST /proposals/{id}/accept`
4. Reject: `POST /proposals/{id}/reject` with optional `comment`

### 6. Handle errors
1. Check `error.code`: branch on stable codes (INVALID_REQUEST, RATE_LIMITED, UNAUTHENTICATED, etc.)
2. 401 → invalid/expired key; rotate key
3. 403 → account lacks API access or required scope
4. 404 → resource not found or outside account access (no disclosure)
5. 409 → conflict or write in progress; check `Retry-After`
6. 422 → malformed request or idempotency key reused with different body
7. 429 → rate limited; wait for `Retry-After`
8. 500 → server error; quote `X-PF-Trace-Id` header to support
9. 503 → key verification temporarily unavailable; retry with backoff

## Common gotchas

- **Leaked keys**: Revocation takes ~2 minutes to propagate; treat leaked keys as live until then. Rotate by creating replacement, updating integration, verifying traffic, then revoking old key.
- **Cursor assumptions**: Never parse, edit, construct, or persist cursor contents. If rejected after API update, restart from first page.
- **Idempotency without key**: Timed-out write may still complete. Always read affected resource before retrying without idempotency key.
- **404 disclosure**: Resources outside your account return 404 (not 403), so API doesn't disclose existence.
- **Price fields**: `basePriceCents` in proposals is creator list price, not payout. Payout is returned in read endpoints after fees.
- **Creator API alpha**: Requires one-time access approval; check Settings → API for request link.
- **Timestamp filters**: Keep `updatedAfter` fixed while paginating for incremental sync; don't update it mid-pagination.
- **Concurrent retries**: Avoid concurrent retry loops when rate limited; add jitter if many workers share a key.
- **409 IDEMPOTENCY_IN_PROGRESS**: First request still running; wait for `Retry-After` before retrying.
- **422 IDEMPOTENCY_KEY_REUSED**: Same key with different body; generate new key for different request.

## Verification checklist

Before submitting work:
- [ ] API key stored in secret manager, never in code or version control
- [ ] Correct endpoint chosen (`/api/v1` for Partner, `/api/creators/v1` for Creator)
- [ ] `Authorization: Bearer` header present on all requests
- [ ] Pagination: following `nextCursor` until `hasMore` is `false`
- [ ] Write operations: using `Idempotency-Key` header (UUID v4)
- [ ] Error handling: branching on `error.code`, not HTTP status alone
- [ ] Rate limiting: respecting `Retry-After` header on 429
- [ ] Timestamps: using ISO 8601 format for date/time filters
- [ ] Cursor handling: passing opaque cursor unchanged, not parsing it
- [ ] Test with small `limit` before scaling to production

## Resources

- **Full documentation index**: https://docs.passionfroot.me/llms.txt — comprehensive page-by-page navigation for all endpoints
- **Authentication guide**: https://docs.passionfroot.me/guides/authentication — key creation, rotation, scope management
- **Rate limits & pagination**: https://docs.passionfroot.me/guides/rate-limits and https://docs.passionfroot.me/guides/pagination — handling backpressure and cursor pagination
- **Quickstart**: https://docs.passionfroot.me/quickstart — first request walkthrough and error handling patterns

---

> For additional documentation and navigation, see: https://docs.passionfroot.me/llms.txt