Okouro docs

Sales run through two objects. An opportunity is a potential deal that advances through pipeline stages. A quote is a priced proposal attached to an opportunity that you send to the client and eventually accept or decline.

1. Create an opportunity

An opportunity belongs to a client and sits on a stage: identified, qualified, proposed, negotiation, won, or lost.

POST /opportunities HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "client_id": "0190a1c2-...",
  "name": "Website rebuild",
  "stage": "qualified",
  "probability": 50,
  "estimated_value": "48000.00",
  "expected_close_date": "2026-03-31"
}

Returns 201 Created with an OpportunityResponse. probability is an integer 0-100.

See the pipeline as a board with GET /opportunities/board, which groups opportunities by stage. Advance a deal by updating its stage with PUT /opportunities/{id}. GET /opportunities/{id} returns the opportunity together with its client, quotes, and activities.

2. Create a quote

A quote prices an opportunity through one or more lines. A line is either rate_based (days x day rate) or fixed (a flat amount).

POST /quotes HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "opportunity_id": "0190a1c2-...",
  "valid_until": "2026-02-28",
  "lines": [
    {
      "kind": "rate_based",
      "profile_label": "Senior Developer",
      "days": "20",
      "day_rate": "800.00",
      "discount_percent": "0"
    },
    {
      "kind": "fixed",
      "profile_label": "Discovery workshop",
      "fixed_amount": "3000.00",
      "discount_percent": "0"
    }
  ]
}

Returns 201 Created with a QuoteResponse in draft status. A new quote takes its “bill to” details from the client unless you pass a bill_to override. discount_percent is a decimal string 0-100.

3. Send, accept, or decline

Send the quote to the client:

POST /quotes/{id}/send HTTP/1.1
Authorization: Bearer <access_token>

Then record the outcome:

POST /quotes/{id}/accept HTTP/1.1
Authorization: Bearer <access_token>
POST /quotes/{id}/decline HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json

{ "reason": "Over budget" }

The quote status moves draft -> sent -> accepted or declined (it can also become expired). Acting out of order returns 409.

4. Download the PDF

GET /quotes/{id}/pdf HTTP/1.1
Authorization: Bearer <access_token>

Returns 200 OK with Content-Type: application/pdf and an attachment filename. This is the one endpoint that does not return JSON.

Profitability and masking

GET /quotes/{id} returns the quote plus a profitability block (revenue, cost, margin percent) and the related opportunity and client. Cost and margin are null for consultant-role callers; revenue is always visible (see Roles and permissions).

Endpoints at a glance

ActionMethodPathSuccess
List opportunitiesGET/opportunities200
BoardGET/opportunities/board200
Create opportunityPOST/opportunities201
Update opportunityPUT/opportunities/{id}200
Create quotePOST/quotes201
Get quoteGET/quotes/{id}200
SendPOST/quotes/{id}/send200
AcceptPOST/quotes/{id}/accept200
DeclinePOST/quotes/{id}/decline200
Download PDFGET/quotes/{id}/pdf200

When a quote is accepted, stand up delivery with Run a mission.