Coperniq opportunities API
The opportunities API from Coperniq — 3 operation(s) for opportunities.
The opportunities API from Coperniq — 3 operation(s) for opportunities.
openapi: 3.1.0
info:
title: API Key accounts opportunities API
version: 1.0.0
servers:
- url: https://api.coperniq.io/v1
description: Production server
tags:
- name: opportunities
paths:
/opportunities:
get:
operationId: list-opportunities
summary: List Opportunities
description: 'Retrieve a paginated list of opportunities.
Supports:
- Pagination (`page_size`, `page`)
- Date filtering (`updated_after`, `updated_before`)
- Sorting (`order_by`, default: desc)
- Field search (`title`, `address`, `primaryName`, `primaryPhone`, `primaryEmail`)
- Full text search (`q`)
**Note:** The `/requests` path is an alias for `/opportunities` and will continue to work until users are individually notified and migrated.
**Note:** If an opportunity has no `title` (empty or whitespace-only), the response returns the parent account''s `title` instead. The stored value is not modified — this is a read-time fallback only.
'
tags:
- opportunities
parameters:
- name: page_size
in: query
description: Number of items per page (max 100)
required: false
schema:
type: integer
default: 20
- name: page
in: query
description: Page number (1-based)
required: false
schema:
type: integer
default: 1
- name: updated_after
in: query
description: Filter items updated after this timestamp (ISO 8601)
required: false
schema:
type: string
format: date-time
- name: updated_before
in: query
description: Filter items updated before this timestamp (ISO 8601)
required: false
schema:
type: string
format: date-time
- name: order_by
in: query
description: Sort order for results
required: false
schema:
$ref: '#/components/schemas/OpportunitiesGetParametersOrderBy'
- name: include_virtual_properties
in: query
description: Whether to include virtual properties in the response. Defaults to false unless explicitly set to true.
required: false
schema:
type: boolean
default: false
- name: include_archived
in: query
description: Whether to include archived (inactive) records in the response. By default only active records are returned.
required: false
schema:
type: boolean
default: false
- name: q
in: query
description: Full text search query
required: false
schema:
type: string
- name: title
in: query
description: Title search query
required: false
schema:
type: string
- name: address
in: query
description: Address search query
required: false
schema:
type: string
- name: primaryName
in: query
description: Contact name search query
required: false
schema:
type: string
- name: primaryPhone
in: query
description: Contact phone search query
required: false
schema:
type: string
- name: primaryEmail
in: query
description: Contact email search query
required: false
schema:
type: string
- name: x-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: List of opportunities
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Opportunity'
'401':
description: Authentication failed
content:
application/json:
schema:
$ref: '#/components/schemas/ListOpportunitiesRequestUnauthorizedError'
post:
operationId: create-opportunity
summary: Create Opportunity
description: 'Create a new opportunity with required and optional fields.
Required fields:
- `title`: Opportunity title/name
- `address`: Opportunity location
- `trades`: Array of trade types
Optional fields:
- `accountId`: Link to existing account
- `workflowId`: Link to workflow
- `phaseId`: Link to phase
- `value`: Opportunity value
- `size`: Opportunity size
- `confidence`: Confidence score (0-100)
- `primaryEmail`/`primaryPhone`: Contact information
- `contacts`: Contact IDs only (no name, email, phone, etc.). The contacts must be created first via POST /contacts.
- `custom`: Custom fields object
Note: If primaryEmail or primaryPhone is provided, a contact will be automatically created or matched.
**Note:** The `/requests` path is an alias for `/opportunities` and will continue to work until users are individually notified and migrated.
'
tags:
- opportunities
parameters:
- name: allow_new_options
in: query
description: Whether to allow creation of new dropdown options during record creation
required: false
schema:
type: boolean
default: false
- name: match_by
in: query
description: Field to use for matching existing records
required: false
schema:
$ref: '#/components/schemas/OpportunitiesPostParametersMatchBy'
- name: match_found_strategy
in: query
description: Strategy to use when a match is found
required: false
schema:
$ref: '#/components/schemas/OpportunitiesPostParametersMatchFoundStrategy'
- name: x-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: Matching opportunity found
content:
application/json:
schema:
$ref: '#/components/schemas/Opportunity'
'400':
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOpportunityRequestBadRequestError'
'401':
description: Authentication failed
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOpportunityRequestUnauthorizedError'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/OpportunityUpsert'
/opportunities/search:
get:
operationId: search-opportunities
summary: Search Opportunities
description: "Search opportunities using up to two filters (prop1/op1/value1 and optionally prop2/op2/value2), combined with `logic` (AND/OR).\n\nProperties:\n- `propX` can be a standard field (e.g., `status`, `title`, `city`, `type`, `accountId`, etc.) or a custom property key name.\n- Use the `property key` from your company settings.\n- Filter by parent account with `accountId`. `clientId` is accepted as a deprecated alias for backwards compatibility.\n\nOperators (`opX`):\n- Equality: `eq`, `neq`\n- Numeric/datetime comparisons: `gt`, `gte`, `lt`, `lte`\n- Text/string matching: `contains` (case-insensitive)\n- Lists: `in`, `nin` (CSV list in `valueX`)\n- Ranges: `between` (use `valueX` as `from,to`)\n- Existence: `exists` is not supported for custom properties due to performance limitations. Use `eq` or `neq` instead.\n\nValue formats:\n- `in`/`nin`: lists can be provided as:\n - Plain CSV: `value1=OPEN,ACTIVE`\n - Quoted CSV (to include commas inside a value): `value1=\"Last, First\",Other`\n - JSON array: `value1=[\"Last, First\",\"Other\"]`\n- `between`: `from,to` (e.g., `value1=2025-01-01,2025-12-31` or `value1=10,20`)\n- Dates should be ISO 8601 strings; numeric-like values on custom properties are matched against both numeric and text representations.\n\nExamples:\n- status equals ACTIVE: `?prop1=status&op1=eq&value1=ACTIVE`\n- custom id equals 1234: `?prop1=legacy_tool_project_id&op1=eq&value1=1234`\n- title contains \"Solar\": `?prop1=name&op1=contains&value1=Solar`\n- status IN (ACTIVE, ON_HOLD) AND city = Austin: `?prop1=status&op1=in&value1=ACTIVE,ON_HOLD&logic=and&prop2=city&op2=eq&value2=Austin`\n\n**Note:** The `/requests` path is an alias for `/opportunities` and will continue to work until users are individually notified and migrated.\n\n**Note:** If an opportunity has no `title` (empty or whitespace-only), the response returns the parent account's `title` instead. The stored value is not modified — this is a read-time fallback only.\n"
tags:
- opportunities
parameters:
- name: prop1
in: query
description: First field to filter (standard or custom keyName)
required: true
schema:
type: string
- name: op1
in: query
description: Operator for prop1
required: true
schema:
$ref: '#/components/schemas/OpportunitiesSearchGetParametersOp1'
- name: value1
in: query
description: Value for prop1 (comma-separated values for in/nin or between)
required: true
schema:
type: string
- name: logic
in: query
description: Logical combination when both prop1 and prop2 are provided
required: false
schema:
$ref: '#/components/schemas/OpportunitiesSearchGetParametersLogic'
- name: prop2
in: query
description: Optional second field to filter
required: false
schema:
type: string
- name: op2
in: query
description: Operator for prop2
required: false
schema:
$ref: '#/components/schemas/OpportunitiesSearchGetParametersOp2'
- name: value2
in: query
description: Value for prop2 (comma-separated values for in/nin or between)
required: false
schema:
type: string
- name: page_size
in: query
description: Number of items per page (max 100)
required: false
schema:
type: integer
default: 20
- name: page
in: query
description: Page number (1-based)
required: false
schema:
type: integer
default: 1
- name: order_by
in: query
description: Sort order for results
required: false
schema:
$ref: '#/components/schemas/OpportunitiesSearchGetParametersOrderBy'
- name: include_archived
in: query
description: Whether to include archived (inactive) records in the response. By default only active records are returned.
required: false
schema:
type: boolean
default: false
- name: x-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: List of opportunities matching filters
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Opportunity'
'400':
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/SearchOpportunitiesRequestBadRequestError'
'401':
description: Authentication failed
content:
application/json:
schema:
$ref: '#/components/schemas/SearchOpportunitiesRequestUnauthorizedError'
/opportunities/{opportunityId}:
get:
operationId: get-opportunity
summary: Get Opportunity
description: 'Retrieve a specific opportunity by ID
**Note:** The `/requests` path is an alias for `/opportunities` and will continue to work until users are individually notified and migrated.
**Note:** If the opportunity has no `title` (empty or whitespace-only), the response returns the parent account''s `title` instead. The stored value is not modified — this is a read-time fallback only.
'
tags:
- opportunities
parameters:
- name: opportunityId
in: path
description: Opportunity identifier
required: true
schema:
type: integer
- name: include_virtual_properties
in: query
description: Whether to include virtual properties in the response. Defaults to false unless explicitly set to true.
required: false
schema:
type: boolean
default: false
- name: include_archived
in: query
description: Whether to include archived (inactive) records in the response. By default only active records are returned.
required: false
schema:
type: boolean
default: false
- name: x-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: Opportunity details
content:
application/json:
schema:
$ref: '#/components/schemas/Opportunity'
'401':
description: Authentication failed
content:
application/json:
schema:
$ref: '#/components/schemas/GetOpportunityRequestUnauthorizedError'
'404':
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/GetOpportunityRequestNotFoundError'
patch:
operationId: update-opportunity
summary: Update Opportunity
description: 'Update an existing opportunity. Supports partial updates.
Updatable fields:
- Standard fields (value, size, status, confidence, etc.)
- Workflow fields (workflowId, phaseId)
- Contact information (primaryEmail, primaryPhone)
- Contacts (contact IDs only, no name, email, phone, etc.)
- Custom fields (through custom object)
Note: Updates are atomic - either all fields update or none do.
> **Changing account association is not supported via update.** To move an opportunity to a different account, delete and re-create it under the new account.
**Note:** The `/requests` path is an alias for `/opportunities` and will continue to work until users are individually notified and migrated.
'
tags:
- opportunities
parameters:
- name: opportunityId
in: path
description: Opportunity identifier
required: true
schema:
type: integer
- name: allow_new_options
in: query
description: Whether to allow creation of new dropdown options during record creation
required: false
schema:
type: boolean
default: false
- name: x-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: Opportunity updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Opportunity'
'400':
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateOpportunityRequestBadRequestError'
'401':
description: Authentication failed
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateOpportunityRequestUnauthorizedError'
'404':
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateOpportunityRequestNotFoundError'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/OpportunityUpsert'
delete:
operationId: delete-opportunity
summary: Delete Opportunity
description: 'Delete a specific opportunity by ID
**Note:** The `/requests` path is an alias for `/opportunities` and will continue to work until users are individually notified and migrated.
'
tags:
- opportunities
parameters:
- name: opportunityId
in: path
description: Opportunity identifier
required: true
schema:
type: integer
- name: x-api-key
in: header
required: true
schema:
type: string
responses:
'200':
description: Successful response
'401':
description: Authentication failed
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteOpportunityRequestUnauthorizedError'
'404':
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteOpportunityRequestNotFoundError'
components:
schemas:
OpportunityProjectManager:
type: object
properties:
id:
type: integer
firstName:
type: string
lastName:
type: string
email:
type: string
phone:
type:
- string
- 'null'
avatarUrl:
type:
- string
- 'null'
title: OpportunityProjectManager
OpportunitiesPostResponsesContentApplicationJsonSchemaCode:
type: string
enum:
- UNAUTHORIZED
title: OpportunitiesPostResponsesContentApplicationJsonSchemaCode
GetOpportunityRequestUnauthorizedError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesOpportunityIdGetResponsesContentApplicationJsonSchemaCode'
title: GetOpportunityRequestUnauthorizedError
OpportunitiesSearchGetParametersOp1:
type: string
enum:
- eq
- neq
- gt
- gte
- lt
- lte
- contains
- in
- nin
- between
title: OpportunitiesSearchGetParametersOp1
DeleteOpportunityRequestUnauthorizedError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesOpportunityIdDeleteResponsesContentApplicationJsonSchemaCode'
title: DeleteOpportunityRequestUnauthorizedError
OpportunitiesOpportunityIdGetResponsesContentApplicationJsonSchemaCode:
type: string
enum:
- NOT_FOUND
title: OpportunitiesOpportunityIdGetResponsesContentApplicationJsonSchemaCode
OpportunitiesGetResponsesContentApplicationJsonSchemaCode:
type: string
enum:
- UNAUTHORIZED
title: OpportunitiesGetResponsesContentApplicationJsonSchemaCode
ProjectStatus:
type: string
enum:
- ACTIVE
- ON_HOLD
- CANCELLED
- COMPLETED
description: 'Status of the project:
* `ACTIVE` - Project is active and in progress
* `ON_HOLD` - Project is temporarily paused
* `CANCELLED` - Project has been cancelled
* `COMPLETED` - Project has been completed
'
title: ProjectStatus
CreateOpportunityRequestUnauthorizedError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesPostResponsesContentApplicationJsonSchemaCode'
title: CreateOpportunityRequestUnauthorizedError
DeleteOpportunityRequestNotFoundError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesOpportunityIdDeleteResponsesContentApplicationJsonSchemaCode'
title: DeleteOpportunityRequestNotFoundError
OpportunitiesSearchGetParametersOrderBy:
type: string
enum:
- asc
- desc
default: asc
title: OpportunitiesSearchGetParametersOrderBy
OpportunitiesPostParametersMatchBy:
type: string
enum:
- title
- primaryEmail
- primaryPhone
- address
default: title
title: OpportunitiesPostParametersMatchBy
UpdateOpportunityRequestUnauthorizedError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesOpportunityIdPatchResponsesContentApplicationJsonSchemaCode'
title: UpdateOpportunityRequestUnauthorizedError
Opportunity:
type: object
properties:
id:
type: integer
description: Unique identifier
createdAt:
type: string
format: date-time
description: Creation timestamp
updatedAt:
type: string
format: date-time
description: Last update timestamp
title:
type: string
description: Record title/name
description:
type:
- string
- 'null'
description: Record description
address:
type: array
items:
type: string
description: An array containing a single string, which represents the full opportunity location/address.
isActive:
type: boolean
description: Whether the record is active
primaryEmail:
type:
- string
- 'null'
format: email
description: Primary contact email
primaryPhone:
type:
- string
- 'null'
description: Primary contact phone
number:
type: integer
description: Sequential opportunity number
createdBy:
oneOf:
- $ref: '#/components/schemas/UserSummary'
- type: 'null'
description: User who created the record. Null when the record was created by a non-user actor (e.g. automation or a contact).
updatedBy:
oneOf:
- $ref: '#/components/schemas/UserSummary'
- type: 'null'
description: User who last edited a field on the record, derived from the changelog. Null when the record has never been edited or the last edit was made by a non-user actor.
custom:
type: object
additionalProperties:
description: Any type
description: Custom fields
trades:
type: array
items:
type: string
description: Array of trade types
value:
type:
- number
- 'null'
format: double
description: Deal value
size:
type:
- number
- 'null'
format: double
description: Deal size
confidence:
type:
- number
- 'null'
format: double
description: Deal confidence score (0-100)
workflowId:
type:
- integer
- 'null'
description: Associated workflow ID
accountId:
type:
- integer
- 'null'
description: Associated account ID
geoLocation:
type: array
items:
type: string
description: Latitude/Longitude in "lat,lon" format
imageUrl:
type:
- string
- 'null'
description: Image URL for the opportunity
streetViewUrl:
type:
- string
- 'null'
description: Street view image URL
city:
type: string
zipcode:
type: string
state:
type: string
street:
type: string
phase:
oneOf:
- $ref: '#/components/schemas/OpportunityPhase'
- type: 'null'
phaseInstances:
type: array
items:
$ref: '#/components/schemas/PhaseInstance'
description: Ordered list of phase instances for the opportunity
owner:
oneOf:
- $ref: '#/components/schemas/OpportunityOwner'
- type: 'null'
salesRep:
oneOf:
- $ref: '#/components/schemas/OpportunitySalesRep'
- type: 'null'
projectManager:
oneOf:
- $ref: '#/components/schemas/OpportunityProjectManager'
- type: 'null'
jurisdiction:
oneOf:
- $ref: '#/components/schemas/OpportunityJurisdiction'
- type: 'null'
lastActivity:
type:
- string
- 'null'
format: date-time
phaseId:
type:
- integer
- 'null'
workflowName:
type: string
description: 'Name of the associated workflow.
'
title: Opportunity
OpportunitiesOpportunityIdDeleteResponsesContentApplicationJsonSchemaCode:
type: string
enum:
- NOT_FOUND
title: OpportunitiesOpportunityIdDeleteResponsesContentApplicationJsonSchemaCode
OpportunityPhase:
type: object
properties:
id:
type: integer
name:
type: string
type:
type: string
title: OpportunityPhase
UpdateOpportunityRequestNotFoundError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesOpportunityIdPatchResponsesContentApplicationJsonSchemaCode'
title: UpdateOpportunityRequestNotFoundError
ListOpportunitiesRequestUnauthorizedError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesGetResponsesContentApplicationJsonSchemaCode'
title: ListOpportunitiesRequestUnauthorizedError
PhaseTemplateSummary:
type: object
properties:
id:
type: integer
name:
type: string
type:
type: string
redSla:
type:
- integer
- 'null'
yellowSla:
type:
- integer
- 'null'
title: PhaseTemplateSummary
GetOpportunityRequestNotFoundError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesOpportunityIdGetResponsesContentApplicationJsonSchemaCode'
title: GetOpportunityRequestNotFoundError
OpportunitiesSearchGetParametersOp2:
type: string
enum:
- eq
- neq
- gt
- gte
- lt
- lte
- contains
- in
- nin
- between
title: OpportunitiesSearchGetParametersOp2
OpportunitiesSearchGetParametersLogic:
type: string
enum:
- and
- or
default: and
title: OpportunitiesSearchGetParametersLogic
OpportunitiesPostParametersMatchFoundStrategy:
type: string
enum:
- skip
- replace
- enrich
default: skip
description: '- skip: Return existing record without changes
- replace: Replace existing record with new data
- enrich: Update only empty fields in existing record
'
title: OpportunitiesPostParametersMatchFoundStrategy
OpportunitiesGetParametersOrderBy:
type: string
enum:
- asc
- desc
default: asc
title: OpportunitiesGetParametersOrderBy
PhaseInstanceStatus:
type: string
enum:
- NOT_STARTED
- IN_PROGRESS
- COMPLETED
title: PhaseInstanceStatus
PhaseInstance:
type: object
properties:
id:
type: integer
name:
type: string
status:
$ref: '#/components/schemas/PhaseInstanceStatus'
position:
type: integer
type:
type: string
phaseTemplateId:
type: integer
phaseTemplate:
$ref: '#/components/schemas/PhaseTemplateSummary'
title: PhaseInstance
UpdateOpportunityRequestBadRequestError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesOpportunityIdPatchResponsesContentApplicationJsonSchemaCode'
field:
type: string
description: Field that caused the validation error (if applicable)
title: UpdateOpportunityRequestBadRequestError
OpportunityJurisdiction:
type: object
properties:
id:
type: integer
name:
type: string
uuid:
type: string
title: OpportunityJurisdiction
SearchOpportunitiesRequestUnauthorizedError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesSearchGetResponsesContentApplicationJsonSchemaCode'
title: SearchOpportunitiesRequestUnauthorizedError
CreateOpportunityRequestBadRequestError:
type: object
properties:
message:
type: string
code:
$ref: '#/components/schemas/OpportunitiesPostResponsesContentApplicationJsonSchemaCode'
field:
type: string
description: Field that caused the validation error (if applicable)
title: CreateOpportunityRequestBadRequestError
OpportunityOwner:
type: object
properties:
id:
type: integer
firstName:
type: string
lastName:
type: string
email:
type: string
phone:
type:
- string
- 'null'
avatarUrl:
type:
- string
- 'null'
title: OpportunityOwner
OpportunitiesSearchGetResponsesContentApplicationJsonSchemaCode:
type: string
enum:
- UNAUTHORIZED
title: OpportunitiesSearchGetResponsesContentApplicationJsonSchemaCode
UserSummary:
type: object
properties:
id:
type: integer
firstName:
type:
- string
- 'null'
lastName:
type:
- string
- 'null'
email:
type:
- string
- 'null'
format: email
avatarUrl:
type:
- string
- 'null'
description: Minimal user representation used in responses
title: UserSummary
OpportunityUpsert:
type: object
properties:
title:
type: string
description: Opportunity title/name
description:
type:
- string
- 'null'
description: Opportunity description
address:
type: array
items:
type: string
description: An array containing a single string, which represents the full opportunity location/address.
trades:
type: array
items:
type: string
description: Array of trade types
workflowId:
type:
- integer
- 'null'
description: ID of associated workflow
value:
type: number
format: double
description: Project value
size:
type: number
format: double
description: Project size
status:
$ref: '#/components/schemas/ProjectStatus'
primaryEmail:
type: string
format: email
description: Primary contact email
primaryPhone:
type: string
description: Primary contact phone
contacts:
type: array
items:
type: integer
description: Contact IDs only (no name, email, phone, etc.). The contacts must be created first via POST /contacts.
custom:
type: object
additionalProperties:
description: Any type
description: Custom fields
required:
- title
- address
- trades
description: 'Used for both create and update. `accountId` is only accepted on create — passing it on a PATCH update will return a 400 error.
'
title: OpportunityUpsert
# --- truncated at 32 KB (33 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/coperniq/refs/heads/main/openapi/coperniq-opportunities-api-openapi.yml