Skip to content

Add services to an offer

POST
/offers/{offerId}/services
curl --request POST \
--url https://apisandbox.puurk.com/offers/example/services \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "services": [ { "service_id": "svc_7Hk2LqRm", "quantity": 1, "merge_contract_id": "example" } ] }'

Add one or more services to an existing offer

offerId
required
string

ID of the offer

Services to add

Media typeapplication/json

Body for POST /offers/{offerId}/services. Note the field names differ from the OfferService response shape: only service_id, quantity and merge_contract_id are writable here. The service name and line amount always come from the organization’s service catalog.

Services can also be supplied inline on POST /offers, in the services array of the offer body — that path creates the offer and its lines in one call, and is the one to reach for when you are creating the offer anyway. Use this endpoint to add lines to an offer that already exists.

object
services
required

Between 1 and 500 service lines.

Array<object>
>= 1 items <= 500 items
object
service_id
required

Must match a service belonging to the offer’s organization, otherwise the request fails with service_not_found.

string
Example
svc_7Hk2LqRm
quantity
required

Greater than 0. Fractional quantities are allowed.

number
Example
1
merge_contract_id

Optional merge contract to attach the line to.

string

Services added; returns the re-priced offer

Media typeapplication/json
object
id

Unique identifier for the offer

string
type

client — a plan for a specific client; requires lead_id. template — a shareable, client-less plan (the provider app calls these “Templates”); lead_id, lead_name and uid are always null on one.

Null on offers created before the type was recorded, until the backfill stamps them. Newly created offers are never null — an offer created with a lead_id and no type is stored as client.

string
nullable
Allowed values: template client
lead_id

The client this plan is for. Required when type is client or omitted. On a template it is always null in the response: one sent in the request is ignored rather than rejected.

string
nullable
lead_name

Always null on a template offer.

string
nullable
uid

Always null on a template offer.

string
nullable
location_id
string
merge_contract_id
string
merge_contract_payment_total
number
oid
string
organization_name
string
provider_id

Deprecated

string
provider_name

Deprecated

string
providers
Array<string>
title
string
total_price
number
retail_price
number
retail_price_new
number
credit_total
number
credit_total_new
number
deposit_total
number
deposit_total_new
number
photo_url
string
thumbnail_url
string
accepted_at
string
created_at
string
created_by
string
declined_at
string
expired_at
string
pay_in_full_price
number
payment_option
string
Allowed values: finance cash
postpone_reason
string
Allowed values: expensive finance_options questions nervous not_ready time other
status
string
Allowed values: pending accepted declined expired
down_payment
number
tax_total
number
tax_total_new
number
term_cap
number
terms
Array<object>
object
offer_id

Offer these terms belong to

string
uid

User the terms were generated for

string
down_payment

Down payment in cents

number
financed_amount

Amount financed in cents

number
provider_premium_share

Provider’s share of the premium as a fraction between 0 and 1

number
nullable
term_length

Plan length in months

number
monthly_premium

Premium charged per month in cents

number
monthly_provider_premium

Provider share of the monthly premium in cents

number
nullable
monthly_puurk_premium

Puurk share of the monthly premium in cents

number
nullable
monthly_principal

Principal per month in cents

number
monthly_fees

Fees included in each monthly payment in cents

number
nullable
monthly_payout_fees

Payout fees per month in cents

number
nullable
monthly_provider_fees

Provider fees per month in cents

number
nullable
monthly_payment

Monthly payment in cents

number
monthly_opportunity

Monthly opportunity for the provider in cents

number
nullable
total_amount

Total paid over the plan in cents

number
total_premium

Total premium over the plan in cents

number
total_provider_premium

Provider share of the total premium in cents

number
nullable
total_puurk_premium

Puurk share of the total premium in cents

number
nullable
total_principal

Total principal (down payment plus financed amount) in cents

number
total_fees

Total fees over the plan in cents

number
nullable
total_payout_fees

Total payout fees over the plan in cents

number
nullable
total_provider_fees

Total provider fees over the plan in cents

number
nullable
total_opportunity

Total opportunity for the provider in cents

number
nullable
selected_term
number
service_ids
Array<string>
services
Array<object>
object
service_id
string
service_name
string
quantity
number
original_quantity
number
remaining_quantity
number
amount
number
merge_contract_id
string
notes
string
sold_by

User id of the salesperson

string
credit_ids
Array<string>
credits
Array<object>
object
id
string
credit_id
string
credit_name
string
service_id
string
service_name
string
amount
number
percentage
number
calculated_amount
number
merge_contract_id
string
updated_at
string format: date-time
updated_by
string
plan_number
number
shared_at
string format: date-time
shared_by
string
viewed_at
string format: date-time
Example
{
"type": "template",
"lead_id": "fLp5zssaLLRcKDbh0DpP",
"lead_name": "John Doe",
"uid": "l8zcL5Va8ei6QQlmhe8n",
"location_id": "g9WWX7DJ0ev6WZ2rOhdQ",
"merge_contract_id": null,
"oid": "iQyjWJf77rrVUx8HJshp",
"organization_name": "Acme Medical",
"provider_id": null,
"provider_name": null,
"providers": [
"4NoHg9a7Yf0QODl1IMcE",
"WKVlP1g5arHJdDa2yBir"
],
"title": "Plan 1234",
"payment_option": "finance",
"postpone_reason": "expensive",
"status": "pending"
}

Validation failed. error is invalid_params and message names the offending field, e.g. Invalid value: services[0].quantity must be a number greater than 0.

Media typeapplication/json

The standard error body. error is a stable, machine-readable code — branch on it rather than on message, which is for humans and may change.

object
error

Machine-readable error code.

string
message

Human-readable detail.

string
Example
{
"error": "merchant_account_missing",
"message": "The organization has no merchant account. Complete Stripe Connect onboarding for this organization before generating pricing."
}

Unauthorized

not_found when the offer does not exist, or service_not_found when a service_id matches no service for the offer’s organization.

Media typeapplication/json

The standard error body. error is a stable, machine-readable code — branch on it rather than on message, which is for humans and may change.

object
error

Machine-readable error code.

string
message

Human-readable detail.

string
Example
{
"error": "merchant_account_missing",
"message": "The organization has no merchant account. Complete Stripe Connect onboarding for this organization before generating pricing."
}

The organization is not ready to be priced: merchant_account_missing when it has no merchant account, merchant_account_inactive when its merchant account is not active, or card_method_missing when the account has no card method. All are resolved by completing Stripe Connect onboarding for the organization.

Media typeapplication/json

The standard error body. error is a stable, machine-readable code — branch on it rather than on message, which is for humans and may change.

object
error

Machine-readable error code.

string
message

Human-readable detail.

string
Example
{
"error": "merchant_account_missing",
"message": "The organization has no merchant account. Complete Stripe Connect onboarding for this organization before generating pricing."
}