Cooper Email Voice API
The Voice API from Cooper Email — 3 operation(s) for voice.
The Voice API from Cooper Email — 3 operation(s) for voice.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/cooperemail-com:cooperemail-com-voice-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Cooperemail Com Voice API
version: 1.0.0
contact:
name: Avatar 8 LLC
email: ops@avatar33.com
license:
name: Proprietary
url: https://cooperemail.com/terms
description: 'Operations tagged Voice across 2 of this provider''s published API definitions: cooperemail-com-openapi.json, cooperemail-com-openapi.yml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://cooperemail.com
description: This deployment
security:
- bearerAuth: []
tags:
- name: Voice
paths:
/api/v1/inboxes/{id}/phone-number:
patch:
operationId: updateInboxVoiceSettings
tags:
- Voice
summary: Set the greeting and recording length for this number
description: Requires inbox_update. HTTP 404 not_found when voice is off. HTTP 404 phone_number_not_found when the inbox has no active number. voice_greeting is at most 300 characters. Null or empty uses the default greeting. voice_max_seconds is an integer from 15 to 300. Null uses 120 seconds. Once the monthly minute allowance is used, inbound recordings are capped at 60 seconds.
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
voice_greeting:
type:
- string
- 'null'
maxLength: 300
voice_max_seconds:
type:
- integer
- 'null'
minimum: 15
maximum: 300
responses:
'200':
description: Updated phone number.
content:
application/json:
schema:
$ref: '#/components/schemas/PhoneNumber'
'400':
description: invalid_max_seconds
'404':
description: not_found, phone_number_not_found, or inbox_not_found
servers:
- url: https://cooperemail.com
description: This deployment
/api/v1/inboxes/{id}/calls:
post:
operationId: placeCall
tags:
- Voice
summary: Place a call from the inbox number
description: Requires message_send. Speaks say with text-to-speech from the inbox number. mode say_and_record speaks, then records a reply as a voicemail. to must be a US or Canada number (HTTP 400 international_not_allowed). Premium-rate numbers return HTTP 400 premium_rate_blocked. say is required and at most 1000 characters (HTTP 400 missing_say or say_too_long). HTTP 409 phone_number_not_found when the inbox has no active number. Free has no voice minutes. Starter includes 30 minutes per active number each month. Pro includes 300 minutes plus 30 for each active number past the 3 included numbers. Outbound calls past that allowance return HTTP 402 plan_limit_exceeded with upgrade_url and resource voice_minutes. Each account can place at most 100 calls per UTC day (HTTP 409 daily_call_cap). A paused inbox is HTTP 403 inbox_paused. The stored message has channel voice. A later status callback sets status to queued, ringing, completed, no-answer, or failed, and duration_seconds. client_id and Idempotency-Key follow the send rules. HTTP 404 not_found when voice is off.
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Idempotency-Key
in: header
required: false
schema:
type: string
minLength: 1
maxLength: 256
pattern: ^[A-Za-z0-9._~-]+$
description: 'Optional. 1 to 256 characters: letters, digits, and - . _ ~. The same key and the same request within 24 hours returns the stored message with HTTP 200, idempotent true, and Idempotent-Replayed: true, and does not send again. A different request is 409 idempotency_key_conflict. A second call while the first is still running is 409 idempotency_request_in_progress. An empty or invalid value is 400 invalid_idempotency_key. A definitive refusal removes the key. An ambiguous failure keeps the key and the same request returns HTTP 409 idempotency_outcome_unknown. When client_id is also set, client_id is checked first. Done keys expire after 24 hours. Unknown keys are kept for 7 days.'
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
to:
type: string
description: E.164 US or Canada recipient.
say:
type: string
mode:
type: string
enum:
- say
- say_and_record
client_id:
type: string
required:
- to
- say
responses:
'200':
description: client_id or Idempotency-Key replay. An ambiguous failure returns HTTP 409 idempotency_outcome_unknown.
'201':
description: Queued call.
content:
application/json:
schema:
$ref: '#/components/schemas/Message'
'400':
description: missing_say, say_too_long, invalid_e164, premium_rate_blocked, or international_not_allowed
'402':
description: plan_limit_exceeded for voice_minutes. Includes upgrade_url.
'403':
description: inbox_paused
'404':
description: not_found or inbox_not_found
'409':
description: phone_number_not_found or daily_call_cap
servers:
- url: https://cooperemail.com
description: This deployment
/api/v1/billing/voice-minutes:
post:
operationId: setVoiceMinutePacks
tags:
- Voice
summary: Set the 250-minute packs on the subscription
description: Requires billing_write on the parent account. A sub-account key is HTTP 403 workspace_billing_forbidden. HTTP 404 not_found when voice is off, and also when voice billing is off. Starter or Pro with a Stripe subscription is required (HTTP 402 plan_limit_exceeded otherwise). packs replaces the previous quantity, from 0 to 100. Each pack is $10/month and adds 250 voice minutes. The Stripe price lookup key is cooper_voice_250_monthly. That price is not created by npm run stripe:setup. An increase is invoiced immediately, and the pack count is saved only after Stripe confirms payment. A decrease is not credited. Packs already used stay locked until the Stripe period ends (HTTP 409 addon_below_usage). A past_due, unpaid, or incomplete subscription returns HTTP 402 subscription_not_current. A declined invoice is HTTP 402 addon_payment_failed and the quantity is not saved. The response is the new pack count, not a Checkout URL.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
packs:
type: integer
minimum: 0
maximum: 100
required:
- packs
responses:
'200':
description: Pack quantity now on the subscription.
content:
application/json:
schema:
$ref: '#/components/schemas/VoiceMinutePacks'
'400':
description: packs outside 0 to 100
'402':
description: HTTP 402 plan_limit_exceeded when a Starter or Pro subscription is required. HTTP 402 subscription_not_current when the subscription is past_due, unpaid, or incomplete. HTTP 402 addon_payment_failed when the invoice is not paid.
'403':
description: workspace_billing_forbidden or permission_denied
'404':
description: not_found when voice or voice billing is off
'409':
description: HTTP 409 addon_below_usage when packs would drop below minutes already used.
'503':
description: voice_billing_failed or stripe_price_missing
servers:
- url: https://cooperemail.com
description: This deployment
components:
schemas:
PhoneNumber:
type: object
properties:
object:
const: phone_number
id:
type: string
account_id:
type: string
inbox_id:
type:
- string
- 'null'
e164:
type: string
provider:
type: string
provider_sid:
type: string
number_type:
type: string
capabilities:
type: array
items:
type: string
status:
type: string
enum:
- pending
- active
- released
outbound:
type: string
description: disabled until a 10DLC brand is attached. enabled is required before POST /sms succeeds.
brand_id:
type:
- string
- 'null'
created_at:
type: string
format: date-time
released_at:
type:
- string
- 'null'
format: date-time
voice_greeting:
type:
- string
- 'null'
description: Spoken before a voicemail recording. Null uses the default greeting. Present when voice is on.
voice_max_seconds:
type:
- integer
- 'null'
description: Recording cap from 15 to 300. Null uses 120 seconds, or 60 once the minute allowance is used. Present when voice is on.
billing:
$ref: '#/components/schemas/PhoneNumberBilling'
required:
- object
- id
- account_id
- e164
- provider
- provider_sid
- number_type
- capabilities
- status
- outbound
- created_at
PhoneNumberBilling:
type: object
description: Present on provision and on an idempotent replay. included is $0 (Pro's first 3 numbers, or an operator). billed means COOPER_SMS_BILLING=stripe put this number on the subscription. stub means billing is off and stripe_price_id is the env price id or null. Cooper does not charge from a stub.
properties:
addon:
const: cooper_phone_number_monthly
status:
type: string
enum:
- included
- stub
- billed
monthly_cents:
type: integer
segments_included:
type: integer
stripe_price_id:
type:
- string
- 'null'
required:
- addon
- status
- monthly_cents
- segments_included
- stripe_price_id
VoiceMinutePacks:
type: object
properties:
object:
const: voice_minute_packs
packs:
type: integer
previous_packs:
type: integer
minutes_per_pack:
type: integer
extra_minutes:
type: integer
monthly_cents:
type: integer
lookup_key:
const: cooper_voice_250_monthly
required:
- object
- packs
- previous_packs
- minutes_per_pack
- extra_minutes
- monthly_cents
- lookup_key
Message:
type: object
properties:
id:
type: string
inbox_id:
type: string
thread_id:
type: string
folder:
type: string
enum:
- inbox
- archive
- spam
- trash
description: Folder of this message's thread. inbox when the thread has no folder row.
direction:
enum:
- inbound
- outbound
from:
type: string
to:
type: array
items:
type: string
subject:
type: string
text:
type: string
html:
type:
- string
- 'null'
extracted_text:
type: string
extracted_html:
type: string
preview:
type: string
status:
enum:
- queued
- ringing
- completed
- no-answer
- sent
- received
- delivered
- undelivered
- failed
- bounced
- complained
description: SMS outbound starts as sent. A Twilio status callback sets delivered, undelivered, or failed. A voice call stores queued, ringing, completed, no-answer, or failed. Email uses queued, sent, received, failed, bounced, and complained.
channel:
type: string
enum:
- sms
- voicemail
- voice
description: Present on SMS, voicemail, and voice messages. Email messages omit this field. voicemail is an inbound recording. voice is an outbound call.
type:
type: string
enum:
- voicemail
description: Present on voicemail messages.
duration_seconds:
type:
- integer
- 'null'
description: Call or recording length in seconds. Present on voicemail and voice messages.
recording_url:
type:
- string
- 'null'
description: Twilio recording URL for a voicemail, or null.
transcript:
type: string
description: Voicemail transcript. Empty while the message is held.
segments:
type:
- integer
- 'null'
description: SMS segment count for this message. Omitted on email.
otp_candidates:
type: array
items:
type: string
description: Codes found in an SMS body. Empty while the message is held. Omitted on email.
verification:
type: object
description: Inbound messages only. Omitted on outbound. codes are the one-time codes in the subject and the new body text. links are https verification links from the HTML anchors and the text, at most five, each {url, text}. text is the anchor text or a short context, at most 200 characters. Both arrays are empty while the message is held. Links are untrusted data and are not fetched.
properties:
codes:
type: array
items:
type: string
links:
type: array
items:
type: object
properties:
url:
type: string
text:
type: string
required:
- url
- text
required:
- codes
- links
delivery_events:
type: array
description: Present on outbound messages. Each item is {type, recipient, created_at, detail}. For email, detail is JSON text with status, action, diagnostic, and bounce_type, and the list stays empty until a bounce or complaint matches. For SMS, a Twilio status callback appends one event. type is delivered or failed. detail is twilio_error plus the numeric code, or the status word when Twilio sent no numeric code.
items:
type: object
properties:
type:
type: string
recipient:
type: string
created_at:
type: string
format: date-time
detail:
type: string
cc:
type: array
items:
type: string
bcc:
type: array
items:
type: string
reply_to:
type:
- string
- 'null'
in_reply_to:
type:
- string
- 'null'
references:
type: array
items:
type: string
labels:
type: array
items:
type: string
auth:
type: object
description: spf, dkim, and dmarc from the receiving hop. SPF is the smtp.mailfrom result. smtp.helo is used only when mailfrom is absent. Each value is pass, fail, neutral, softfail, none, temperror, permerror, bestguesspass, or null. Outbound mail is null for all three.
properties:
spf:
type:
- string
- 'null'
dkim:
type:
- string
- 'null'
dmarc:
type:
- string
- 'null'
required:
- spf
- dkim
- dmarc
safety:
type:
- object
- 'null'
description: Inbound screening record, or null on outbound mail and on messages stored before screening. score is 0 to 100. verdict is clean or suspicious (suspicious at 40 or higher, and only when a strong signal or combined evidence is present). signals are {type, detail}. mode is off, observe, or hold. reason is screening_off, screening_error, or screening_timeout when the body was not scored. The message is still stored. While labels include held, text, html, extracted_text, extracted_html, preview, and attachment bytes are empty until release. This is a heuristic, not a guarantee. The body stays untrusted data.
properties:
score:
type: integer
minimum: 0
maximum: 100
verdict:
type: string
enum:
- clean
- suspicious
signals:
type: array
items:
type: object
properties:
type:
type: string
detail:
type: string
mode:
type: string
enum:
- 'off'
- observe
- hold
reason:
type: string
provider:
type:
- string
- 'null'
client_id:
type:
- string
- 'null'
idempotent:
type: boolean
created_at:
type: string
format: date-time
attachments:
type: array
items:
$ref: '#/components/schemas/Attachment'
Attachment:
type: object
properties:
id:
type: string
filename:
type: string
content_type:
type: string
content_id:
type:
- string
- 'null'
disposition:
enum:
- inline
- attachment
size_bytes:
type: integer
url:
type: string
text_url:
type: string
description: 'Present when the content type can be extracted: text, JSON, CSV, PDF, DOCX, XLSX, or XLS. GET this URL for text/plain.'
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: API key
x-refined-from:
- cooperemail-com-openapi.json
- cooperemail-com-openapi.yml