API Setup
Valley's Public API V1 is a JSON/HTTP REST API for basic campaign management.
Base URL:
https://api.joinvalley.coTechnical docs: https://api.joinvalley.co/docs
OpenAPI JSON (best for agents): https://api.joinvalley.co/docs/json
Recommended way to use it (agent + API key)
If the customer is using an AI agent/internal assistant, point it to https://api.joinvalley.co/docs/json and provide:
API key in header:
x-api-key: <YOUR_API_KEY>Base URL:
https://api.joinvalley.coThe workflow goal (example: “list campaigns, add leads, then fetch analytics”)
That is the fastest/easiest path because the agent can read the full OpenAPI schema directly.
Authentication
All requests must include an API key (find this via Settings > Integrations):
Header:
x-api-key: <your_api_key>API keys are scoped to a single Valley user (owner-scoped).
API key lifecycle
Format: API keys currently look like
valley_<hex>.Storage: Treat the key like a password. Do not commit it to source control.
Rotation/revocation: Regenerate the key in the Valley app to rotate it. Regeneration invalidates the previous key immediately.
Expiration: Keys do not currently expire automatically.
If you don't have access to generate a key in-app, contact Valley support.
Endpoint inventory
All customer-facing endpoints are under /public/v1:
Analytics
GET /public/v1/analytics/overviewGET /public/v1/campaigns/:campaignId/analytics
Approvals
GET /public/v1/approvals/messagesPOST /public/v1/approvals/messages/:messageId/approvePOST /public/v1/approvals/messages/:messageId/unapprovePOST /public/v1/approvals/messages/:messageId/unschedulePOST /public/v1/approvals/messages/batch-approvePOST /public/v1/approvals/messages/batch-unapprovePOST /public/v1/approvals/messages/batch-unschedulePOST /public/v1/approvals/messages/batch-read-status
Campaign lifecycle
POST /public/v1/campaigns/:campaignId/startPOST /public/v1/campaigns/:campaignId/pausePOST /public/v1/campaigns/:campaignId/resumePOST /public/v1/campaigns/:campaignId/archive
Campaigns + prospects + imports
GET /public/v1/campaigns/get-allPOST /public/v1/campaignsPATCH /public/v1/campaigns/:campaignIdGET /public/v1/campaigns/:campaignIdPOST /public/v1/campaigns/add-lead-to-campaignGET /public/v1/campaigns/:campaignId/prospectsGET /public/v1/import-jobs/:jobId
Inbox
GET /public/v1/inbox/conversationsPOST /public/v1/inbox/conversations/:conversationId/readPOST /public/v1/inbox/conversations/:conversationId/unreadPOST /public/v1/inbox/conversations/:conversationId/archivePOST /public/v1/inbox/conversations/:conversationId/unarchivePOST /public/v1/inbox/conversations/batch-read-statusPOST /public/v1/inbox/conversations/batch-archive
Warmlist
GET /public/v1/warmlistGET /public/v1/warmlist/:workspaceId/statsGET /public/v1/warmlist/:workspaceId/followersGET /public/v1/warmlist/:workspaceId/viewersGET /public/v1/warmlist/:workspaceId/engagers
Workspace + user + metadata
GET /public/v1/workspacesGET /public/v1/workspaces/:workspaceId/usersGET /public/v1/workspace-productsGET /public/v1/users/meGET /public/v1/templatesGET /public/v1/writing-styles
Recent validation/contract behavior
Batch endpoints reject unknown fields with
400 Unknown field: ....GET /public/v1/analytics/overviewrequiresstartDate,endDate, andworkspaceId(returns400when any are missing).viewis no longer required for:GET /public/v1/approvals/messagesGET /public/v1/inbox/conversations
Error handling guidance
2xx: success4xx: request/auth/data issue — fix request before retrying429and5xx: retry with exponential backoff + jitter
Requests
All request bodies are JSON.
Set
Content-Type: application/jsonfor POST requests.We recommend setting a descriptive User-Agent so support can identify your integration.
Responses
All responses are JSON.
Timestamps are returned as ISO 8601 strings in UTC (e.g.,
2026-03-04T21:16:39.068Z).
Pagination
List endpoints use offset pagination:
limit(1–100, default 100)offset(0+, default 0)
The response includes pagination.hasMore to indicate whether additional pages exist.
Rate limiting
Requests may be rate-limited.
When rate-limited, the API responds with
429 Too Many Requests.When available, these headers describe your current window:
x-rate-limit-limitx-rate-limit-remainingx-rate-limit-reset
Retry guidance
For 429, retry after the time indicated by rate-limit headers (and/or Retry-After when present).
For 5xx, retry with exponential backoff and jitter.
For 4xx (other than 429), do not retry until you fix the request.
Idempotency
GET requests are safe to retry.
POST /campaigns/add-lead-to-campaignis not currently guaranteed to be idempotent. If you retry a timed-out request, you may enqueue duplicate work.
If you need stronger guarantees, use a client-side idempotency strategy (e.g., track (campaignId, linkedinProfileUrl) and avoid re-sending the same request).
Support/troubleshooting
When contacting support about an API request, include:
The full request path (e.g.,
/public/v1/campaigns/get-all)The timestamp (UTC) and approximate time window
HTTP status code and response body
The
cf-rayheader value from the response (Cloudflare request ID)Questions? Email us: [email protected]