# Retrieve an Appointment Recording — Shilo API Source: https://docs.shilo.ai/api-reference/appointments/get-appointment Retrieve a single appointment recording by its Shilo recording UUID or external recording ID. Returns the Appointment object with user and contact identifiers. Use this endpoint to fetch a single appointment recording by its identifier. You can look up an appointment using either the Shilo-generated recording UUID or the external recording ID that your integration provided when the appointment was ingested. This is useful for confirming that an appointment has been processed or for retrieving its metadata before fetching analysis or transcript data. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/appointments/{identifier} ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Path Parameters The unique identifier for the appointment recording. Two formats are accepted: * `{uuid}` — The Shilo recording UUID (e.g., `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `external_recording_id:{string}` — The external recording ID your integration provided (e.g., `external_recording_id:ext-789`) ## Response A successful request returns HTTP `200` with the matching Appointment object. The Shilo recording UUID for this appointment. Always `"appointment"` for records returned by this endpoint. The ISO-8601 timestamp indicating when the appointment recording was created in Shilo. The Shilo UUID of the user associated with this appointment. `null` if no user is matched. The external user ID provided by your integration at the time the appointment was created. `null` if not provided. The external contact ID provided by your integration at the time the appointment was created. `null` if not provided. The external recording ID provided by your integration, if any. `null` if not provided. ### Error Responses | Status | Description | | ----------------- | --------------------------------------------------------------------------- | | `400 Bad Request` | The `identifier` path parameter is malformed or uses an unsupported format. | | `404 Not Found` | No appointment recording was found matching the provided identifier. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/appointments/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ --header "x-api-key: YOUR_API_KEY" ``` By external recording ID: ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/appointments/external_recording_id:ext-789" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "type": "appointment", "created_date": "2030-09-24T12:34:56Z", "user_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_user_id": "432", "external_contact_id": "4534", "external_recording_id": "ext-789" } ``` # Retrieve Appointment Analysis — Shilo API Source: https://docs.shilo.ai/api-reference/appointments/get-appointment-analysis Retrieve AI-generated analysis for an appointment recording: rating, coaching, summary, disposition, and objections. Poll the progress field until it reaches 100. Use this endpoint to retrieve the AI-generated analysis for an appointment recording. Shilo processes each appointment asynchronously after ingestion, producing coaching feedback, a call rating, conversation summary, disposition outcomes, objection handling insights, and speaker identification. Because processing takes time, you should poll this endpoint and check the `progress` field — results are only fully available once `progress` reaches `100`. ## Endpoint ``` GET https://api.shilo.ai/api/v1/appointments/{identifier}/analysis ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Path Parameters The unique identifier for the appointment recording. Two formats are accepted: * `{uuid}` — The Shilo recording UUID (e.g., `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `external_recording_id:{string}` — The external recording ID your integration provided (e.g., `external_recording_id:ext-789`) ## Response A successful request returns HTTP `200` with a `RecordingAnalysis` object. The top-level fields `id`, `recording_id`, `created_at`, and `progress` are always present. All sub-resource fields (`coaching`, `rating`, `summary`, etc.) are optional and only fully populated once `progress` equals `100`. The UUID of this analysis record. The Shilo recording UUID of the appointment this analysis belongs to. The ISO-8601 timestamp indicating when this analysis was created. A value between `0` and `100` representing how far along the AI processing pipeline this recording is. Poll this endpoint until `progress` equals `100` before reading any result fields. Recommended follow-up actions identified by the AI. Present only after processing completes. The UUID of this action items record. The most important follow-up actions for the rep to take after this appointment. Additional, lower-priority follow-up actions. AI-generated coaching feedback for the rep on this appointment. Present only after processing completes. The UUID of this coaching record. Areas where the rep could have performed better, with specific suggestions. Highlights from the appointment where the rep performed particularly well. The AI-assessed outcome and reasoning for this appointment. Present only after processing completes. The UUID of this disposition record. The determined outcome labels for the appointment (e.g., booked, not interested). A plain-language explanation of why the AI assigned these outcomes. Objections raised by the contact during the appointment. Present only after processing completes. The UUID of this objections record. A list of objections identified in the conversation. A numeric quality rating assigned to the rep's performance on this appointment. Present only after processing completes. The UUID of this rating record. The numeric rating score assigned to the rep's performance. A plain-language explanation of what drove the assigned score. AI-resolved speaker identities for the appointment recording. Present only after processing completes. The UUID of this speakers record. The resolved name of the sales rep in this recording. The resolved name of the client or contact in this recording. A concise AI-generated summary of the appointment. Present only after processing completes. The UUID of this summary record. An object containing the summary text. The full text of the AI-generated appointment summary. Poll this endpoint until `progress` equals `100` before reading result fields such as `coaching`, `rating`, or `summary`. Sub-resource fields are absent or incomplete until processing finishes. ### Error Responses | Status | Description | | ----------------- | --------------------------------------------------------------------------- | | `400 Bad Request` | The `identifier` path parameter is malformed or uses an unsupported format. | | `404 Not Found` | No appointment recording was found matching the provided identifier. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/appointments/ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "id": "a1b2c3d4-0000-4000-8000-111122223333", "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "created_at": "2030-09-24T12:40:00Z", "progress": 100, "action_items": { "id": "a1b2c3d4-0000-4000-8000-aaaaaaaaaaaa", "primary": [ "Send follow-up email with pricing sheet", "Schedule a product demo for next week" ], "secondary": [ "Add contact to nurture sequence" ] }, "coaching": { "id": "a1b2c3d4-0000-4000-8000-bbbbbbbbbbbb", "possible_improvements": [ "Slow down when presenting pricing to allow time for questions", "Ask more open-ended discovery questions early in the call" ], "top_moments": [ "Excellent handling of the budget objection at the 12-minute mark", "Strong rapport-building during the opening" ] }, "disposition": { "id": "a1b2c3d4-0000-4000-8000-cccccccccccc", "outcomes": ["demo_scheduled"], "reasoning": "The contact agreed to a product demo and expressed strong interest in the enterprise plan." }, "objections": { "id": "a1b2c3d4-0000-4000-8000-dddddddddddd", "outcomes": [ "Price is too high", "Need to involve another decision-maker" ] }, "rating": { "id": "a1b2c3d4-0000-4000-8000-eeeeeeeeeeee", "outcome": 82, "reasoning": "The rep demonstrated strong product knowledge and handled objections confidently, with room to improve discovery questioning." }, "speakers": { "id": "a1b2c3d4-0000-4000-8000-ffffffffffff", "user_name": "Jordan Smith", "client_name": "Alex Rivera" }, "summary": { "id": "a1b2c3d4-0000-4000-8000-000000000000", "outcome": { "summary": "Jordan connected with Alex to discuss upgrading from the starter plan. Alex raised concerns about pricing and the need to consult a second decision-maker. Jordan successfully navigated both objections and secured commitment for a follow-up demo next Thursday." } } } ``` # Retrieve Appointment Transcript — Shilo API Source: https://docs.shilo.ai/api-reference/appointments/get-appointment-transcript Retrieve the sanitized transcript for an appointment recording with AI-resolved speaker names. Returns 403 for Follow Up Boss accounts, 409 if speaker resolution is still in progress. Use this endpoint to retrieve the full transcript for an appointment recording. Shilo sanitizes the raw transcript and resolves speaker labels using AI — replacing generic labels like "Speaker 1" with the actual names of the rep and client. Because speaker resolution depends on completed analysis, you should wait until the appointment's `analysis.progress` field reaches `100` before requesting the transcript, or be prepared to handle a `409` response and retry. Accounts integrated with **Follow Up Boss** CRM are not supported for transcript retrieval and will receive a `403 Forbidden` response. ## Endpoint ``` GET https://api.shilo.ai/api/v1/appointments/{identifier}/transcript ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Path Parameters The unique identifier for the appointment recording. Two formats are accepted: * `{uuid}` — The Shilo recording UUID (e.g., `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `external_recording_id:{string}` — The external recording ID your integration provided (e.g., `external_recording_id:ext-789`) ## Response A successful request returns HTTP `200` with a transcript object. The exact shape of the transcript object varies by integration, but will include speaker-attributed text segments with timing information. The transcript response shape may vary depending on your CRM integration. The example below shows a representative structure. Always treat the transcript as a free-form JSON object (`additionalProperties: true` in the OpenAPI spec). Fetch the transcript only after `analysis.progress` equals `100`. If speaker resolution is still in progress, the API returns `409 Conflict` — wait and retry. ### Error Responses | Status | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | The `identifier` path parameter is malformed or uses an unsupported format. | | `403 Forbidden` | Your account is integrated with Follow Up Boss CRM, which does not support transcript retrieval. | | `404 Not Found` | No appointment recording was found matching the provided identifier. | | `409 Conflict` | The transcript is not yet ready. Analysis and speaker resolution are still in progress. Retry after `analysis.progress` reaches `100`. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/appointments/ee6f2136-b94a-4438-9335-3acf5b2a0d31/transcript" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "segments": [ { "speaker": "Jordan Smith", "text": "Hi Alex, thanks for making time today. I wanted to walk you through what an upgrade to our enterprise plan would look like for your team.", "start": 0.0, "end": 8.4 }, { "speaker": "Alex Rivera", "text": "Of course, happy to chat. I did want to bring up the pricing — it seemed a bit higher than what we budgeted for.", "start": 8.7, "end": 15.2 }, { "speaker": "Jordan Smith", "text": "Totally understand. Let me show you how the ROI typically breaks down for teams your size — I think it'll make the number feel a lot more reasonable.", "start": 15.5, "end": 23.1 } ] } ``` # List Appointment Recordings — Shilo API Source: https://docs.shilo.ai/api-reference/appointments/list-appointments Retrieve a paginated list of appointment recordings filtered by user, contact, or date range. Appointments are created automatically via CRM integration, not via API. Use this endpoint to retrieve a paginated list of appointment recordings from your Shilo account. Appointments are created automatically through your CRM integration — they cannot be created directly via the API. You can narrow results by user, contact, or creation date, and page through large result sets using the cursor returned in each response. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/appointments ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Query Parameters The maximum number of appointment records to return per page. Accepted values are between `1` and `100`. An opaque pagination cursor returned in the previous response's `pagination.next_cursor` field. Pass this value to retrieve the next page of results. Omit to start from the beginning. The sort order for results, based on `created_date`. Accepted values are `asc` (oldest first) or `desc` (newest first). Return only appointments created on or after this date and time. Must be an ISO-8601 formatted string (e.g., `2030-01-01T00:00:00Z`). Return only appointments created on or before this date and time. Must be an ISO-8601 formatted string (e.g., `2030-12-31T23:59:59Z`). Filter appointments by the associated user. Accepts a prefix-qualified identifier in one of three formats: * `id:{uuid}` — Shilo user UUID * `external_user_id:{value}` — your external user ID * `{uuid}` — bare Shilo user UUID (shorthand) Filter appointments by the associated contact. Accepts a prefix-qualified identifier in one of three formats: * `id:{uuid}` — Shilo contact UUID * `external_contact_id:{value}` — your external contact ID * `{uuid}` — bare Shilo contact UUID (shorthand) ## Response A successful request returns HTTP `200` with an `AppointmentsResponseDto` object. An array of Appointment objects matching the query filters. The Shilo recording UUID for this appointment. Always `"appointment"` for records returned by this endpoint. The ISO-8601 timestamp indicating when the appointment recording was created in Shilo. The Shilo UUID of the user associated with this appointment. `null` if no user is matched. The external user ID provided by your integration at the time the appointment was created. `null` if not provided. The external contact ID provided by your integration at the time the appointment was created. `null` if not provided. The external recording ID provided by your integration, if any. Use this value in other appointment endpoints with the `external_recording_id:{value}` prefix format. `null` if not provided. Metadata for paginating through additional results. `true` if there are additional pages of results beyond the current response; `false` if this is the last page. An opaque cursor string to pass as the `cursor` query parameter in your next request. Returns `null` when there are no further pages. ### Error Responses | Status | Description | | ------------------ | -------------------------------------- | | `401 Unauthorized` | Missing or invalid `x-api-key` header. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/appointments?limit=50&sort=desc" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "type": "appointment", "created_date": "2030-09-24T12:34:56Z", "user_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_user_id": "432", "external_contact_id": "4534", "external_recording_id": "ext-789" } ], "pagination": { "has_more": false, "next_cursor": null } } ``` # POST /api/v1/calls — Submit a Call for AI Analysis Source: https://docs.shilo.ai/api-reference/calls/create-call Submit a new call recording to Shilo for AI processing. Provide a recording URL, agent details, and contact details. Returns a call_event_id for polling. Use this endpoint to submit a call recording to Shilo for asynchronous AI processing. Shilo will download the audio from the URL you provide, transcribe it, resolve speaker identities, and run your configured AI coaching models against it. Because processing happens in the background, the response is `202 Accepted` — you receive a `call_event_id` that you can use to poll for the call object and its analysis once processing is complete. This endpoint requires a **write-enabled** API key. Requests made with a read-only key will receive a `403 Forbidden` response. ## Endpoint ```text theme={null} POST https://api.shilo.ai/api/v1/calls ``` ## Request Body The request body must be a JSON object conforming to `CreateCallDto`. The following fields are required on every submission. ### Required Fields Your system's unique external identifier for this recording. Shilo stores this as `external_recording_id` on the Call object and you can use it later to retrieve the call via `external_recording_id:{value}`. A publicly accessible URL pointing to the audio file for this call. Shilo's servers must be able to fetch this URL without authentication. Supported formats include MP3, WAV, M4A, and OGG. Total length of the call in seconds. This value is stored on the call and used to contextualize AI analysis outputs. The analysis category that determines which AI coaching rubric is applied to this call (e.g. `"sales"`). Contact your Shilo account team to confirm the categories available for your organization. Your system's unique identifier for the agent on this call. Shilo uses this to match the call to an existing Shilo user record. If no match is found, Shilo will use `user_name` and `user_email` to create or locate the user. Display name of the agent on this call. Used for speaker labeling in the transcript and coaching output. Email address of the agent on this call. Used to look up or create the corresponding Shilo user account. Your system's unique identifier for the contact (lead or prospect) on this call. Shilo uses this to associate the call with an existing contact record. Full display name of the contact on this call. Used for speaker labeling in the transcript and analysis output. ### Optional Fields ISO-8601 timestamp representing when the call actually took place (e.g. `"2030-09-24T14:00:00Z"`). If omitted, Shilo records the ingestion time instead. The phone number the call was placed from, in any standard format. Nullable. The phone number the call was placed to, in any standard format. Nullable. Set to `true` if this was an inbound call received by the agent; `false` if the agent placed the call. Nullable. Override the default AI models applied to this call. Each element must be an object with `model` (string) and `type` (string) properties. If omitted, Shilo uses the models configured for your organization. Nullable. IANA timezone string for the agent (e.g. `"America/New_York"`). Used to localize timestamps in coaching reports. Nullable. URL of the agent's profile picture. Used for display in the Shilo dashboard. Nullable. First name of the contact. If provided alongside `contact_last_name`, Shilo uses these in place of `contact_name` for structured display. Nullable. Last name of the contact. Nullable. Phone number of the contact. Nullable. Array of email addresses associated with the contact. Nullable. Human-readable sales stage name for the contact at the time of this call (e.g. `"Nurture"`). Nullable. Your system's identifier for the contact's sales stage. Nullable. Human-readable lead source name for the contact (e.g. `"Website"`). Nullable. Your system's identifier for the contact's lead source. Nullable. Array of tag strings to apply to the contact (e.g. `["hot-lead", "referral"]`). Nullable. ## Response A successful submission returns HTTP `202 Accepted` with a `CreateCallResponse` body. UUID that tracks this submission through Shilo's async processing pipeline. Save this value — you can pass it as `call_event_id:{uuid}` to `GET /calls/{identifier}` and `GET /calls/{identifier}/analysis` to poll for results. Current processing status of the submission. On initial response this is always `"QUEUED"`. The call progresses through internal states before analysis becomes available. ### Example Response ```json theme={null} { "call_event_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "status": "QUEUED" } ``` Save the `call_event_id` returned in this response. To retrieve the processed call or its AI analysis, use this value as the `identifier` path parameter in the format `call_event_id:{uuid}` — for example: `GET /api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31`. ## Example Request ```bash theme={null} curl --request POST \ --url "https://api.shilo.ai/api/v1/calls" \ --header "x-api-key: YOUR_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "recording_id": "rec-20300924-001", "recording_url": "https://storage.example.com/recordings/rec-20300924-001.mp3", "duration_seconds": 183, "ai_category": "sales", "external_user_id": "agent-432", "user_name": "Jordan Smith", "user_email": "jordan.smith@example.com", "external_contact_id": "lead-4534", "contact_name": "Alex Johnson", "occurred_at": "2030-09-24T14:00:00Z", "incoming": false, "from_number": "(555) 555-1234", "to_number": "(555) 555-5678", "contact_stage": "Nurture", "contact_source": "Website" }' ``` ## Error Responses **400 Bad Request** — Returned when the request body is missing required fields or contains invalid values. The response body includes a `message` field describing the problem. ```json theme={null} { "statusCode": 400, "message": ["recording_url must be a URL address", "duration_seconds must be a number"] } ``` **403 Forbidden** — Returned when your API key is read-only and does not have permission to create calls. ```json theme={null} { "error": "forbidden", "message": "API key is read-only" } ``` # Get a Call Recording — Shilo API GET /api/v1/calls Source: https://docs.shilo.ai/api-reference/calls/get-call Retrieve a single non-roleplay call by Shilo UUID, call event ID, or your external recording ID. Returns the complete Call object with all fields. This endpoint retrieves a single call recording by one of three supported identifier formats. You can look up a call using Shilo's own UUID, the `call_event_id` returned when you submitted the call for processing, or your own external recording identifier. This flexibility means you can integrate Shilo lookups without needing to store Shilo-internal IDs in your own systems. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/calls/{identifier} ``` ## Path Parameter Identifies the call to retrieve. Three formats are accepted: | Format | Example | When to use | | -------------------------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | You already have the Shilo Call UUID (e.g. from `GET /calls`). | | `call_event_id:{uuid}` | `call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | You just submitted a call via `POST /calls` and want to check its status. Use the `call_event_id` value from that response. | | `external_recording_id:{string}` | `external_recording_id:rec-20300924-001` | You want to look up a call using the `recording_id` your system provided at submission time. | ## Response A successful request returns HTTP `200` with the full Call object. Shilo's unique UUID for this call recording. Resource type identifier. Always `"call"` for this endpoint. ISO-8601 timestamp of when the call was ingested by Shilo. Length of the call in seconds. Your system's identifier for the agent on this call. Shilo's UUID for the agent on this call. Your system's identifier for the contact on this call. Shilo's UUID for the contact on this call. The phone number the call originated from, in display format. The phone number the call was placed to, in display format. `true` if the call was inbound (received by the agent); `false` if outbound. Human-readable name of the recording source (e.g. `"Broker"`). Identifier of the recording source. Human-readable sales stage associated with the contact at call time. Identifier of the associated sales stage. The `recording_id` your system supplied when this call was submitted via `POST /calls`. ## Example Requests **Look up by Shilo Call UUID:** ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/calls/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ --header "x-api-key: YOUR_API_KEY" ``` **Look up immediately after submission using `call_event_id`:** ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ --header "x-api-key: YOUR_API_KEY" ``` **Look up using your own external recording ID:** ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/calls/external_recording_id:rec-20300924-001" \ --header "x-api-key: YOUR_API_KEY" ``` ### Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "type": "call", "created_date": "2030-09-24T12:34:56Z", "duration": 120, "external_user_id": "432", "user_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_contact_id": "4534", "contact_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "from_number": "(555) 555-1234", "to_number": "(555) 555-5678", "incoming": true, "source": "Broker", "source_id": "80", "stage": "Agents", "stage_id": "60", "external_recording_id": "ext-123" } ``` ## Error Responses **400 Bad Request** — The `identifier` path parameter is not a valid UUID, or the prefix does not match an accepted format. ```json theme={null} { "statusCode": 400, "message": "Invalid identifier format" } ``` **404 Not Found** — No call matching the provided identifier exists in your organization. ```json theme={null} { "statusCode": 404, "message": "Call not found" } ``` # Retrieve Call Analysis — GET /calls/{identifier}/analysis Source: https://docs.shilo.ai/api-reference/calls/get-call-analysis Retrieve AI-generated call analysis including rating, coaching feedback, summary, disposition, objections, action items, and speaker labels. After you submit a call via `POST /calls`, Shilo processes it asynchronously — transcribing the audio, resolving speaker identities, and running AI coaching models. This endpoint exposes the results of that analysis. Because processing takes time, the response includes a `progress` field (0–100) that you should poll until it reaches `100` before reading analysis results. Individual analysis fields will be `null` until their respective model runs complete. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/calls/{identifier}/analysis ``` ## Path Parameter Identifies the call whose analysis you want to retrieve. The same three formats accepted by `GET /calls/{identifier}` are supported here: | Format | Example | | -------------------------------- | ---------------------------------------------------- | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | `call_event_id:{uuid}` | `call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | `external_recording_id:{string}` | `external_recording_id:rec-20300924-001` | ## Response A successful request returns HTTP `200` with a `RecordingAnalysis` object. Check `progress` before reading analysis fields. Analysis fields (`action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, `summary`) may be `null` while `progress` is less than `100`. Always poll this endpoint until `progress === 100` before consuming these fields in your application. Shilo's unique UUID for this analysis record. The Shilo Call UUID this analysis belongs to. ISO-8601 timestamp of when this analysis record was created. Integer from `0` to `100` representing overall analysis completion. Poll until this value equals `100` before reading results. A value of `100` guarantees all AI models have finished. Follow-up actions the AI identified from the call. `null` until analysis is complete. Unique identifier for this action items result. Array of the most important follow-up actions the agent should take after this call. Array of additional, lower-priority follow-up actions surfaced by the AI. AI-generated coaching feedback for the agent. `null` until analysis is complete. Unique identifier for this coaching result. Array of coaching suggestions — specific behaviors or techniques the agent could improve on the next call. Array of highlights identifying moments in the call where the agent performed particularly well. AI-determined outcome of the call. `null` until analysis is complete. Unique identifier for this disposition result. Array of disposition labels assigned to this call (e.g. `"Appointment Set"`, `"Not Interested"`). The AI's explanation for why it assigned these disposition outcomes. Objections raised by the contact during the call. `null` until analysis is complete. Unique identifier for this objections result. Array of objection strings identified in the conversation (e.g. `"Not the right time"`, `"Already working with an agent"`). AI-generated numeric rating of the call. `null` until analysis is complete. Unique identifier for this rating result. Numeric score for the call based on your organization's AI coaching rubric. The AI's explanation of the factors that drove this rating. Resolved speaker identity mapping for the transcript. `null` until analysis is complete. Unique identifier for this speakers result. The agent's display name as resolved by Shilo's speaker identification model. The contact's display name as resolved by Shilo's speaker identification model. AI-generated summary of the call. `null` until analysis is complete. Unique identifier for this summary result. Object containing the summary content. The structure of this object may vary by AI model configuration — it typically contains one or more text fields with the generated summary. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis" \ --header "x-api-key: YOUR_API_KEY" ``` ### Example Response ```json theme={null} { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "created_at": "2030-09-24T12:35:00Z", "progress": 100, "action_items": { "id": "act-001", "primary": [ "Send the client a follow-up email with the property details discussed", "Schedule a showing for next Tuesday" ], "secondary": [ "Add client to the monthly newsletter" ] }, "coaching": { "id": "coa-001", "possible_improvements": [ "Ask more open-ended discovery questions before presenting listings", "Confirm the client's timeline earlier in the conversation" ], "top_moments": [ "Handled the pricing objection effectively at 2:14", "Strong rapport-building in the opening 30 seconds" ] }, "disposition": { "id": "dis-001", "outcomes": ["Appointment Set"], "reasoning": "The agent and contact agreed on a showing for next Tuesday at 10am." }, "objections": { "id": "obj-001", "outcomes": [ "Price is too high", "Need to talk to spouse first" ] }, "rating": { "id": "rat-001", "outcome": 82, "reasoning": "Strong opener and close; opportunity to improve mid-call discovery." }, "speakers": { "id": "spk-001", "user_name": "Jordan Smith", "client_name": "Alex Johnson" }, "summary": { "id": "sum-001", "outcome": { "text": "Jordan spoke with Alex about available listings in the Eastside neighborhood. Alex expressed interest in a 3-bedroom home under $650k. They agreed on a Tuesday showing and Jordan will send a curated list of properties beforehand." } } } ``` ## Error Responses **400 Bad Request** — The identifier format is invalid. ```json theme={null} { "statusCode": 400, "message": "Invalid identifier format" } ``` **404 Not Found** — No call matching the provided identifier exists in your organization. ```json theme={null} { "statusCode": 404, "message": "Call not found" } ``` # Retrieve a Call Transcript — GET /calls/{identifier} Source: https://docs.shilo.ai/api-reference/calls/get-call-transcript Get a sanitized call transcript with AI-resolved speaker names. Returns 409 until analysis is complete. Not supported for Follow Up Boss accounts. This endpoint returns the full transcript of a call with AI-resolved speaker labels applied. Shilo identifies each segment of the conversation and maps it to either the agent or the contact by name, giving you a clean, readable record of who said what. Because speaker resolution depends on the AI analysis pipeline completing successfully, the transcript is not available until `progress` on the analysis endpoint reaches `100`. Requesting the transcript before that point returns a `409 Conflict` response. This endpoint is **not available** for organizations connected to Follow Up Boss. Requests from Follow Up Boss-integrated accounts will receive a `403 Forbidden` response regardless of analysis status. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/calls/{identifier}/transcript ``` ## Path Parameter Identifies the call whose transcript you want to retrieve. The same three formats accepted by `GET /calls/{identifier}` are supported here: | Format | Example | | -------------------------------- | ---------------------------------------------------- | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | `call_event_id:{uuid}` | `call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | `external_recording_id:{string}` | `external_recording_id:rec-20300924-001` | ## Response A successful request returns HTTP `200` with a transcript object containing speaker-labeled segments. The exact structure of the transcript JSON varies by AI model configuration, but each segment includes the speaker's resolved name and the text they spoke. Before requesting the transcript, poll `GET /calls/{identifier}/analysis` until the `progress` field equals `100`. Requesting the transcript while analysis is still running will return a `409 Conflict` error. Speaker resolution must be fully complete before transcripts are served. ### Example Response ```json theme={null} { "call_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "segments": [ { "speaker": "Jordan Smith", "start_time": 0.0, "end_time": 5.4, "text": "Hi Alex, this is Jordan calling from Premier Realty. How are you doing today?" }, { "speaker": "Alex Johnson", "start_time": 5.6, "end_time": 10.2, "text": "Hi Jordan, I'm doing well, thanks for calling." }, { "speaker": "Jordan Smith", "start_time": 10.5, "end_time": 18.9, "text": "Great to hear it. I wanted to follow up on the properties you were looking at in the Eastside neighborhood. Did you get a chance to review the ones I sent over?" } ] } ``` ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/transcript" \ --header "x-api-key: YOUR_API_KEY" ``` ## Error Responses **400 Bad Request** — The identifier format is invalid or cannot be parsed. ```json theme={null} { "statusCode": 400, "message": "Invalid identifier format" } ``` **403 Forbidden** — Your organization's CRM integration does not support transcript access. This error is returned for all Follow Up Boss-connected accounts. ```json theme={null} { "statusCode": 403, "message": "Transcript access is not supported for this integration" } ``` **404 Not Found** — No call matching the provided identifier exists in your organization. ```json theme={null} { "statusCode": 404, "message": "Call not found" } ``` **409 Conflict** — The transcript is not yet available because AI analysis and speaker resolution have not completed. Poll `GET /calls/{identifier}/analysis` until `progress` equals `100`, then retry this request. ```json theme={null} { "statusCode": 409, "message": "Transcript is not ready. Analysis must complete before the transcript can be served." } ``` # List Call Recordings — Shilo API GET /api/v1/calls Source: https://docs.shilo.ai/api-reference/calls/list-calls Retrieve a paginated list of non-roleplay call recordings. Filter by user, contact, stage, source, or date range. Returns Call objects. This endpoint returns a paginated list of call recordings associated with your Shilo organization. Only non-roleplay calls are returned. You can narrow results using filters for the owning agent, associated contact, sales stage, recording source, or creation date range. Results are returned in cursor-based pages to support efficient traversal of large datasets. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/calls ``` ## Query Parameters Maximum number of call records to return in a single page. Defaults to `50`. Maximum allowed value is `100`. Opaque pagination cursor returned as `next_cursor` in a previous response. Pass this value to retrieve the next page of results. Omit to start from the beginning. Sort order for results by creation date. Accepts `"asc"` (oldest first) or `"desc"` (newest first). Defaults to `"asc"`. Return only calls created on or after this timestamp. Must be a valid ISO-8601 datetime string (e.g. `2030-01-01T00:00:00Z`). Return only calls created on or before this timestamp. Must be a valid ISO-8601 datetime string. Use together with `created_date_gte` to define a date range. Filter calls by their recording source ID. Corresponds to `source_id` on the Call object. Filter calls by the agent who owns them. Supports three formats: * `{uuid}` — Shilo User UUID directly * `id:{uuid}` — explicit Shilo UUID prefix * `external_user_id:{value}` — your own system's agent identifier Filter calls by the associated contact. Supports three formats: * `{uuid}` — Shilo Contact UUID directly * `id:{uuid}` — explicit Shilo UUID prefix * `external_contact_id:{value}` — your own system's contact identifier Filter calls by the sales stage ID associated with the contact at the time of the call. ## Response A successful request returns HTTP `200` with a `CallsResponseDto` object containing a `data` array of Call objects and a `pagination` object. Array of Call objects matching the query. Shilo's unique UUID for this call recording. Resource type identifier. Always `"call"` for this endpoint. ISO-8601 timestamp of when the call was ingested by Shilo. Length of the call in seconds. Your system's identifier for the agent on this call. Shilo's UUID for the agent on this call. Your system's identifier for the contact on this call. Shilo's UUID for the contact on this call. The phone number the call originated from, in display format. The phone number the call was placed to, in display format. `true` if the call was inbound (received by the agent); `false` if outbound. Human-readable name of the recording source (e.g. `"Broker"`). Identifier of the recording source. Human-readable sales stage associated with the contact at call time. Identifier of the associated sales stage. The `recording_id` your system supplied when this call was submitted via `POST /calls`. Pagination metadata for iterating through large result sets. `true` if there are additional pages of results beyond the current page. Opaque cursor string to pass as the `cursor` query parameter to retrieve the next page. `null` when `has_more` is `false`. ### Example Response ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "type": "call", "created_date": "2030-09-24T12:34:56Z", "duration": 120, "external_user_id": "432", "user_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_contact_id": "4534", "contact_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "from_number": "(555) 555-1234", "to_number": "(555) 555-5678", "incoming": true, "source": "Broker", "source_id": "80", "stage": "Agents", "stage_id": "60", "external_recording_id": "ext-123" } ], "pagination": { "has_more": true, "next_cursor": "eyJjcmV..." } } ``` ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/calls?limit=50&sort=desc&created_date_gte=2030-01-01T00:00:00Z" \ --header "x-api-key: YOUR_API_KEY" ``` ## Error Responses **401 Unauthorized** — Returned when the API key is missing or invalid. Missing `x-api-key` (or `Authorization: Bearer`) header: ```json theme={null} { "error": "unauthorized", "message": "Missing API key" } ``` Unrecognized or revoked key: ```json theme={null} { "error": "unauthorized", "message": "Invalid API key" } ``` # Retrieve a Single Agent Coaching Agenda — Shilo API Source: https://docs.shilo.ai/api-reference/coaching/get-agenda Retrieve a single agent coaching agenda and its completion state. The agenda URL can be used to direct the agent to complete their 1:1 coaching session. Use this endpoint to retrieve metadata for a single coaching agenda: the period it belongs to, its generation and completion state, and, when available, an authenticated Shilo web deep link the agent can use to open their coaching session. This endpoint does not return the generated agenda's questions or body content. Use the `agenda_url` field to deep-link agents into their coaching session from your own app, email notifications, or CRM workflows. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/coaching/agendas/{agendaId} ``` ## Authentication Include your API key in the request header: ```text theme={null} x-api-key: YOUR_API_KEY ``` ## Path Parameters The unique identifier of the coaching agenda to retrieve. You can obtain agenda IDs from the [List Period Agendas](/api-reference/coaching/list-period-agendas) endpoint. ## Response ### 200 — Success Returns a `CoachingAgenda` object. Unique identifier for the coaching agenda (UUID). The coaching period this agenda was generated for. Your Shilo integration identifier. Shilo user ID of the agent this agenda belongs to. May be `null` if the user record was removed after agenda generation. Your system's user ID for the agent. Human-readable title for the agenda (e.g. `"June coaching"`). May be `null` if not yet assigned. Cadence of the parent coaching period: `weekly`, `semimonthly`, or `monthly`. ISO-8601 date marking the start of the parent coaching period. ISO-8601 date marking the end of the parent coaching period. ISO-8601 date marking the end of the review window during which the agent can submit the agenda. Generation status of the agenda. One of `queued`, `processing`, `ready`, `failed`, or `not_eligible`. Whether the agent has completed the agenda. ISO-8601 timestamp of when the agent completed the agenda. `null` if not completed. Whether the agenda was completed before `review_period_end`. `null` if not completed. Whether post-submission analysis has produced a stored summary. Authenticated Shilo web deep link the agent can use to open their coaching session. Present only for `ready` agendas with exactly one active user mapping. Requires normal Shilo web authentication and does not contain an API key or login token. `null` otherwise. ISO-8601 timestamp of when the agenda was created. ISO-8601 timestamp of the most recent update to this agenda. ### 400 — Bad Request The `agendaId` path parameter is malformed. ### 401 — Unauthorized Your API key is missing or invalid. ### 404 — Not Found No coaching agenda with the given `agendaId` exists in your organization. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/coaching/agendas/c1a2b3d4-e5f6-7890-abcd-ef1234567890" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "id": "c1a2b3d4-e5f6-7890-abcd-ef1234567890", "period_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "integration_id": "a3c9e214-1f2b-4d78-bb01-7e5f9c3d0a12", "user_id": "f7e6d5c4-b3a2-1098-fedc-ba9876543210", "external_user_id": "usr_abc123", "title": "June coaching", "cadence": "weekly", "period_start": "2026-06-01", "period_end": "2026-06-07", "review_period_end": "2026-06-14", "generation_status": "ready", "is_completed": false, "completed_at": null, "completed_on_time": null, "analysis_ready": true, "agenda_url": "https://app.shilo.ai/i/a3c9e214-1f2b-4d78-bb01-7e5f9c3d0a12/insights/agent/usr_abc123/coaching/c1a2b3d4-e5f6-7890-abcd-ef1234567890?itemType=coaching", "created_date": "2026-06-08T13:00:00Z", "updated_date": "2026-06-08T13:00:00Z" } ``` Use the `agenda_url` field to link agents directly to their coaching agenda from your own app or notification system. The link opens the agent's coaching session in Shilo and requires normal Shilo web authentication; it does not carry an API key or login token. # Retrieve a Single Coaching Period — Shilo Coaching Source: https://docs.shilo.ai/api-reference/coaching/get-period Retrieve a single coaching period and its team digest once processing completes. Check the digest_status field before reading digest content. Use this endpoint to retrieve the full details of a single coaching period, including its date range, review window status, and team digest. The team digest becomes available once `digest_status` transitions to `completed`. Always check `digest_status` before attempting to read digest content to avoid acting on incomplete data. ## Endpoint ``` GET https://api.shilo.ai/api/v1/coaching/periods/{periodId} ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The unique identifier of the coaching period to retrieve. You can obtain period IDs from the [List Periods](/api-reference/coaching/list-periods) endpoint. ## Response ### 200 — Success Returns a `CoachingPeriodDetail` object. This extends the base `CoachingPeriod` fields with digest content once processing is complete. Unique identifier for the coaching period (UUID). The cadence for this period: `weekly`, `semimonthly`, or `monthly`. Calendar date on which call data collection begins (inclusive). Format: `YYYY-MM-DD`. Calendar date on which call data collection ends (inclusive). Format: `YYYY-MM-DD`. Inclusive UTC calendar-date deadline for agents to complete their coaching agendas. Format: `YYYY-MM-DD`. `open` through the end of `review_period_end` in UTC; `closed` thereafter. Processing status of the team digest. `pending` while being generated; `completed` when the digest content is available. ISO-8601 timestamp of when the period record was created. ISO-8601 timestamp of the most recent update to this period record. ### 400 — Bad Request The `periodId` path parameter is malformed. ### 401 — Unauthorized Your API key is missing or invalid. ### 404 — Not Found No coaching period with the given `periodId` exists in your organization. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/coaching/periods/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "cadence": "weekly", "period_start": "2026-06-01", "period_end": "2026-06-07", "review_period_end": "2026-06-14", "review_status": "closed", "digest_status": "completed", "created_date": "2026-06-08T12:34:56Z", "updated_date": "2026-06-15T03:12:00Z" } ``` Check `digest_status == "completed"` before reading digest content. Digest content is only available on this detail endpoint once processing is complete. # Retrieve 1:1 Coaching Settings — Shilo Coaching API Source: https://docs.shilo.ai/api-reference/coaching/get-settings Retrieve 1:1 coaching settings for your Shilo integration: cadence, enabled status, custom focus text, custom questions, and per-user usage limits. Use this endpoint to inspect the current 1:1 Coaching configuration for your Shilo integration. The response tells you whether coaching is enabled, how frequently coaching periods are generated (cadence), any custom focus text or questions that have been configured for your organization, and the usage limits that govern how much AI coaching content can be generated per period. ## Endpoint ``` GET https://api.shilo.ai/api/v1/coaching/settings ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Response ### 200 — Success Returns a `CoachingSettings` object. The unique identifier of your Shilo integration. Whether the 1:1 Coaching feature is currently enabled for your integration. This is the configured feature toggle, independent of usage limits. The frequency at which new coaching periods are created. One of: `weekly`, `semimonthly`, `monthly`. Custom coaching content configured for your organization. A free-text coaching focus description that guides the AI when generating agent coaching agendas. Array of custom coaching questions included in every agent agenda. Unique identifier for this question. Display order of the question in the agenda (ascending, minimum 0). The text of the coaching question shown to agents. Controls how much AI coaching content can be generated per period. Organization-wide coaching limit in seconds. `null` means unlimited; `0` means coaching generation is fully blocked. Per-user coaching limit in seconds. `null` means unlimited; `0` means coaching generation is fully blocked for each user. ### 401 — Unauthorized Your API key is missing or invalid. ### 404 — Not Found No coaching settings were found for your integration. Coaching may not yet be configured. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/coaching/settings" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "integration_id": "a3c9e214-1f2b-4d78-bb01-7e5f9c3d0a12", "enabled": true, "cadence": "weekly", "customization": { "focus": "Focus on objection handling and discovery question quality.", "questions": [ { "id": "q1", "order": 0, "text": "What was the biggest challenge you faced on calls this week?" }, { "id": "q2", "order": 1, "text": "Which objection did you struggle with most, and how did you handle it?" } ] }, "usage_limits": { "integration_limit_seconds": 36000, "per_user_limit_seconds": 3600 } } ``` # List All Agent Coaching Agendas for a Period — Shilo Source: https://docs.shilo.ai/api-reference/coaching/list-period-agendas List all agent coaching agendas for a period, including ready, failed, and not-eligible agendas. Filter by user ID to find a specific agent's agenda. Use this endpoint to retrieve metadata for all coaching agendas associated with a specific coaching period. Each item includes the agenda's generation and completion state and, when available, an authenticated Shilo web deep link. This endpoint does not return the generated agendas' questions or body content. Results include agendas of all statuses, including those still queued or processing, those that failed generation, and agents who were not eligible during that period. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/coaching/periods/{periodId}/agendas ``` ## Authentication Include your API key in the request header: ```text theme={null} x-api-key: YOUR_API_KEY ``` ## Path Parameters The unique identifier of the coaching period whose agendas you want to list. Obtain period IDs from the [List Periods](/api-reference/coaching/list-periods) endpoint. ## Query Parameters Maximum number of results to return per page. Maximum value is `100`. Pagination cursor from a previous response's `pagination.next_cursor`. Omit to start from the beginning. Sort order by agenda creation date. Accepted values: `asc`, `desc`. Filter results to a specific agent's agenda. Accepted formats: * `id:{uuid}` — prefixed Shilo UUID * `external_user_id:{string}` — your system's user ID * `{uuid}` — bare Shilo UUID ## Response ### 200 — Success Returns a `CoachingAgendasResponseDto` object containing a `data` array of `CoachingAgenda` objects and a `pagination` block. Array of coaching agenda objects for this period. Unique identifier for the coaching agenda (UUID). The coaching period this agenda belongs to. Your Shilo integration identifier. Shilo user ID of the agent this agenda was generated for. May be `null` if the user record was removed. Your system's user ID for the agent. Human-readable title for the agenda (e.g. `"June coaching"`). May be `null` if not yet generated. Cadence of the parent period: `weekly`, `semimonthly`, or `monthly`. ISO-8601 date marking the start of the parent coaching period. ISO-8601 date marking the end of the parent coaching period. ISO-8601 date marking the end of the review window during which the agent can submit the agenda. Generation status of the agenda. One of `queued`, `processing`, `ready`, `failed`, or `not_eligible`. Whether the agent has completed the agenda. ISO-8601 timestamp of when the agent completed the agenda. `null` if not completed. Whether the agenda was completed before `review_period_end`. `null` if not completed. Whether post-submission analysis has produced a stored summary. Authenticated Shilo web deep link the agent can use to open their coaching session. Present only for `ready` agendas with exactly one active user mapping. Requires normal Shilo web authentication and does not contain an API key or login token. `null` otherwise. ISO-8601 timestamp of when the agenda was created. ISO-8601 timestamp of the most recent update to this agenda. Pagination metadata. Whether additional pages of results exist. Cursor for the next page. `null` when `has_more` is `false`. ### 400 — Bad Request The `periodId` path parameter or one or more query parameters contain invalid values. ### 401 — Unauthorized Your API key is missing or invalid. ### 404 — Not Found No coaching period with the given `periodId` exists in your organization. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/coaching/periods/ee6f2136-b94a-4438-9335-3acf5b2a0d31/agendas?limit=50&sort=desc" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "data": [ { "id": "c1a2b3d4-e5f6-7890-abcd-ef1234567890", "period_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "integration_id": "a3c9e214-1f2b-4d78-bb01-7e5f9c3d0a12", "user_id": "f7e6d5c4-b3a2-1098-fedc-ba9876543210", "external_user_id": "usr_abc123", "title": "June coaching", "cadence": "weekly", "period_start": "2026-06-01", "period_end": "2026-06-07", "review_period_end": "2026-06-14", "generation_status": "ready", "is_completed": false, "completed_at": null, "completed_on_time": null, "analysis_ready": true, "agenda_url": "https://app.shilo.ai/i/a3c9e214-1f2b-4d78-bb01-7e5f9c3d0a12/insights/agent/usr_abc123/coaching/c1a2b3d4-e5f6-7890-abcd-ef1234567890?itemType=coaching", "created_date": "2026-06-08T13:00:00Z", "updated_date": "2026-06-08T13:00:00Z" } ], "pagination": { "has_more": false, "next_cursor": null } } ``` This endpoint returns agendas of all statuses: `queued`, `processing`, `ready`, `failed`, and `not_eligible`. Filter on the `generation_status` field in your application to show only relevant records to managers or agents. # List All 1:1 Coaching Periods — Shilo Coaching API Source: https://docs.shilo.ai/api-reference/coaching/list-periods Retrieve a paginated list of 1:1 coaching periods for your integration. Filter by cadence. Each period shows its review status and digest readiness. Use this endpoint to retrieve the list of coaching periods generated for your Shilo integration. Each period represents a discrete time window during which call data is collected for agent coaching agendas. You can use this endpoint to discover active and past periods, check whether the review window is still open, and determine whether the team digest has been generated yet. ## Endpoint ``` GET https://api.shilo.ai/api/v1/coaching/periods ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Query Parameters Maximum number of results to return per page. Maximum value is `100`. Pagination cursor from a previous response's `pagination.next_cursor`. Omit to start from the beginning. Sort order by created date. Accepted values: `asc`, `desc`. Defaults to `desc` so the most recent period appears first. Filter results to a specific coaching cadence. Accepted values: `monthly`, `semimonthly`, `weekly`. Omit to return periods of all cadences. ## Response ### 200 — Success Returns a `CoachingPeriodsResponseDto` containing a `data` array of coaching period objects and a `pagination` block. Array of coaching period objects. Unique identifier for the coaching period (UUID). The cadence for this period: `weekly`, `semimonthly`, or `monthly`. Calendar date on which call data collection for this period begins (inclusive). Format: `YYYY-MM-DD`. Calendar date on which call data collection for this period ends (inclusive). Format: `YYYY-MM-DD`. Inclusive UTC calendar-date deadline for agents to complete their coaching agendas. Format: `YYYY-MM-DD`. Whether the review window is currently open. `open` through the end of `review_period_end` in UTC; `closed` thereafter. Processing status of the team-level digest for this period. `pending` while the digest is being generated; `completed` when the digest is available on the period detail. ISO-8601 timestamp of when the period record was created. ISO-8601 timestamp of the most recent update to this period record. Pagination metadata. Whether additional pages of results exist. Cursor to pass as the `cursor` query parameter for the next page. `null` when `has_more` is `false`. ### 400 — Bad Request One or more query parameters contain invalid values. ### 401 — Unauthorized Your API key is missing or invalid. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/coaching/periods?limit=10&sort=desc&cadence=weekly" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "cadence": "weekly", "period_start": "2026-06-01", "period_end": "2026-06-07", "review_period_end": "2026-06-14", "review_status": "open", "digest_status": "pending", "created_date": "2026-06-08T12:34:56Z", "updated_date": "2026-06-08T12:34:56Z" } ], "pagination": { "has_more": false, "next_cursor": null } } ``` `review_status` is `open` through the end of `review_period_end` in UTC, and transitions to `closed` after that deadline passes. Use this field to determine whether agents can still submit their agendas for the period. # Create a Contact — Shilo API Reference Source: https://docs.shilo.ai/api-reference/contacts/create-contact Create a new contact in Shilo with name, email, phone, and your external contact ID for cross-system linking. Requires a write-enabled API key. Use this endpoint to add a new contact to your Shilo organization. You must supply `external_contact_id`, `name`, `first_name`, and `last_name`. The `external_contact_id` links the Shilo contact record back to your CRM or data source. All other fields are optional and can be populated now or updated later. This endpoint requires a **write-enabled** API key — read-only keys will receive a `403` response. ## Endpoint ```text theme={null} POST https://api.shilo.ai/api/v1/contacts ``` ## Authentication Include your write-enabled API key in the request header: ```text theme={null} x-api-key: YOUR_API_KEY ``` ## Request Body Your system's unique identifier for this contact. Used to correlate the Shilo record with your CRM or external data source. Full display name of the contact (e.g. `"Jamie Customer"`). Contact's first name. Contact's last name. Primary phone number for the contact. Any standard formatting is accepted. One or more email addresses to associate with this contact. Human-readable label for the contact's current pipeline stage (e.g. `"Negotiation"`). Your system's ID for the pipeline stage. Useful for programmatic stage filtering later. Human-readable label for the contact's lead source (e.g. `"Zillow"`). Your system's ID for the lead source. An array of tag labels to apply to the contact for segmentation and filtering. ## Response A successful request returns HTTP `201` with the newly created Contact object. ### Response Fields The Shilo-assigned UUID for the newly created contact. The external ID you supplied at creation. Full display name of the contact. Contact's first name. Contact's last name. Primary phone number. Email addresses associated with the contact. Pipeline stage label. Pipeline stage ID from your system. Lead source label. Lead source ID from your system. Tags applied to the contact. ISO-8601 timestamp indicating when this contact was created in Shilo. ### Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_contact_id": "4534", "name": "Jamie Customer", "first_name": "Jamie", "last_name": "Customer", "phone": "(555) 555-9999", "emails": ["jamie@example.com"], "stage": "Negotiation", "stage_id": "stage-99", "source": "Zillow", "source_id": "src-7", "tags": ["hot-lead", "q4"], "created_date": "2024-09-01T10:00:00Z" } ``` ## Error Codes | Status | Meaning | | ------ | --------------------------------------------------------------- | | `400` | Invalid request body — check required fields and value formats. | | `403` | Your API key is read-only. A write-enabled key is required. | ## Example Request ```bash theme={null} curl -X POST "https://api.shilo.ai/api/v1/contacts" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "external_contact_id": "4534", "name": "Jamie Customer", "first_name": "Jamie", "last_name": "Customer", "phone": "(555) 555-9999", "emails": ["jamie@example.com"], "stage": "Negotiation", "stage_id": "stage-99", "source": "Zillow", "source_id": "src-7", "tags": ["hot-lead", "q4"] }' ``` # Get a Contact — Shilo API Reference Source: https://docs.shilo.ai/api-reference/contacts/get-contact Retrieve a single contact by Shilo UUID or your external contact ID. Supports id:uuid and external_contact_id: prefix patterns for flexible lookup. Use this endpoint to retrieve a single contact record from your Shilo organization. You can identify the contact using their Shilo UUID, a prefixed UUID, or your own external contact ID — whichever is most convenient for your integration. This flexibility lets you look up contacts without maintaining a separate mapping table between your system and Shilo. ## Endpoint ``` GET https://api.shilo.ai/api/v1/contacts/{identifier} ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the contact. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External contact ID | `external_contact_id:4534` | ## Response A successful request returns HTTP `200` with a Contact object. ### Response Fields The Shilo-assigned UUID for this contact. The contact ID from your external CRM or system of record. Full display name of the contact. Contact's first name. Contact's last name. Primary phone number for the contact. Email addresses associated with the contact. Human-readable label for the contact's current pipeline stage. Your system's ID for the pipeline stage. Human-readable label for the contact's lead source. Your system's ID for the lead source. Tags applied to the contact. ISO-8601 timestamp indicating when this contact was created in Shilo. ### Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_contact_id": "4534", "name": "Jamie Customer", "first_name": "Jamie", "last_name": "Customer", "phone": "(555) 555-9999", "emails": ["jamie@example.com"], "stage": "Negotiation", "stage_id": "stage-99", "source": "Zillow", "source_id": "src-7", "tags": ["hot-lead"], "created_date": "2024-09-01T10:00:00Z" } ``` ## Error Codes | Status | Meaning | | ------ | ------------------------------------------------------ | | `400` | The identifier format is invalid or malformed. | | `404` | No contact was found matching the provided identifier. | ## Example Requests ### Look up by plain Shilo UUID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ -H "x-api-key: YOUR_API_KEY" ``` ### Look up by prefixed Shilo UUID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts/id:ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ -H "x-api-key: YOUR_API_KEY" ``` ### Look up by external contact ID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts/external_contact_id:4534" \ -H "x-api-key: YOUR_API_KEY" ``` # Get Contact Metrics — Shilo API Reference Source: https://docs.shilo.ai/api-reference/contacts/get-contact-metrics Retrieve dashboard-aligned call performance metrics for a specific contact. Filter by date range, source, stage, team, and call direction. Use this endpoint to retrieve call performance metrics for a specific contact. The data returned mirrors what you see in the Shilo web dashboard and can be scoped by date range, lead source, pipeline stage, team, and call direction. This makes it straightforward to embed contact-level analytics in your own reporting tools or CRM views. ## Endpoint ``` GET https://api.shilo.ai/api/v1/contacts/{identifier}/metrics ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the contact. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External contact ID | `external_contact_id:4534` | ## Query Parameters Inclusive lower bound of the date range as an ISO date or date-time (e.g. `2024-10-01T00:00:00Z`). Date-only values use UTC start of day. Defaults to UTC start of day 29 days ago. Inclusive upper bound of the date range as an ISO date or date-time. Date-only values use UTC end of day. Defaults to the request time. Comma-separated list of source IDs to filter by (e.g. `src-1,src-2`). Returns metrics only for calls associated with the specified lead sources. Comma-separated list of stage IDs to filter by. Returns metrics only for calls where the contact was in one of the specified pipeline stages. Comma-separated list of team IDs to filter by. Returns metrics only for calls made by agents on the specified teams. Filter by call direction. Accepted values: `all`, `inbound`, `outbound`. ## Response A successful request returns HTTP `200` with a `Metrics` object. The `Metrics` shape is the same as returned by the integration-level and user-level metrics endpoints, scoped to this contact's activity. The `Metrics` object uses the same calculations shown in the Shilo web app's insights view. Field names and structure align with the dashboard data model. ## Error Codes | Status | Meaning | | ------ | -------------------------------------------------- | | `400` | Invalid query parameters or malformed identifier. | | `401` | Missing or invalid API key. | | `404` | No contact found matching the provided identifier. | ## Example Request ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts/ee6f2136-b94a-4438-9335-3acf5b2a0d31/metrics?type=outbound&date_gte=2024-10-01T00:00:00Z" \ -H "x-api-key: YOUR_API_KEY" ``` ### Filter by external contact ID with a custom date range ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts/external_contact_id:4534/metrics?date_gte=2024-10-01T00:00:00Z&date_lte=2024-10-31T23:59:59Z&type=all" \ -H "x-api-key: YOUR_API_KEY" ``` # Get Contact Signal — Shilo API Reference Source: https://docs.shilo.ai/api-reference/contacts/get-contact-signal Retrieve the latest AI-derived behavioral and communication profile for a contact, including DISC dimensions and coaching-oriented context. Use this endpoint to fetch the latest Shilo Signal for a specific contact. A Shilo Signal is the latest AI-derived behavioral and communication profile for the contact, distilled from their interactions with your team. Use it to tailor communication, prepare for the next conversation, and adapt your approach to the contact's style. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/contacts/{identifier}/signal ``` ## Authentication Include your API key in the request header: ```text theme={null} x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the contact. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External contact ID | `external_contact_id:4534` | ## Response A successful request returns HTTP `200` with a `ContactSignal` object describing the contact's latest behavioral and communication profile. The `ContactSignal` object contains the following required fields: * `contact_id`: the Shilo UUID for the contact. * `external_contact_id`: your system's contact ID (nullable). * `id`, `name`, `aboutMe`, `reasoning`, `conflictStyle`, `coreMotivators`, `socialOrientation`, `fearsAndAvoidances`, `maxPerformanceRecs`, and `psychologicalSummary`. * `DISC`: a required object containing the following required fields: * `dominance` * `influence` * `steadiness` * `conscientiousness` * `profileName` * `profileType` The profile fields above are present on a successful response. `external_contact_id` may be `null`. ## Error Codes | Status | Meaning | | ------ | ----------------------------------------------------------------------------- | | `400` | Invalid or malformed identifier. | | `404` | No contact found matching the provided identifier. | | `500` | The stored signal payload for this contact is invalid or could not be parsed. | ## Example Request ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts/ee6f2136-b94a-4438-9335-3acf5b2a0d31/signal" \ -H "x-api-key: YOUR_API_KEY" ``` ### Look up by external contact ID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts/external_contact_id:4534/signal" \ -H "x-api-key: YOUR_API_KEY" ``` # List Contacts — Shilo API Reference Source: https://docs.shilo.ai/api-reference/contacts/list-contacts Retrieve a paginated list of contacts in your Shilo organization. Filter by external ID, phone, email, or name. Supports cursor-based pagination. Use this endpoint to retrieve all contacts in your Shilo organization. Results are paginated and can be filtered by external contact ID, phone number, email address, or name. Use the `cursor` returned in the pagination object to walk through large result sets page by page. ## Endpoint ``` GET https://api.shilo.ai/api/v1/contacts ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Query Parameters Maximum number of contacts to return per page. Accepted range is 1–100. Pagination cursor returned by a previous response. Pass this value to retrieve the next page of results. Sort order by created date. Accepted values: `asc`, `desc`. Filter by your CRM or external system's contact ID. Exact match only. Filter by phone number. Matched after digit-normalizing both the query and stored values, so formatting differences are ignored. Filter by email address. Case-insensitive exact match. Filter by contact name. Case-insensitive partial match — useful for search-as-you-type UIs. ## Response A successful request returns HTTP `200` with a `ContactsResponseDto` object. ### Response Fields An array of Contact objects matching your query filters. The Shilo-assigned UUID for this contact. The contact ID from your external CRM or system of record. Full display name of the contact. Contact's first name. Contact's last name. Primary phone number for the contact. List of email addresses associated with the contact. Human-readable label for the contact's current pipeline stage. Your system's ID for the pipeline stage. Human-readable label for the contact's lead source. Your system's ID for the lead source. Tags applied to the contact. ISO-8601 timestamp indicating when this contact was created in Shilo. Pagination metadata for the current response. `true` if additional pages of results exist beyond the current page. Cursor value to pass in your next request to retrieve the following page. `null` when no further pages are available. ### Example Response ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_contact_id": "4534", "name": "Jamie Customer", "first_name": "Jamie", "last_name": "Customer", "phone": "(555) 555-9999", "emails": ["jamie@example.com"], "stage": "Negotiation", "stage_id": "stage-99", "source": "Zillow", "source_id": "src-7", "tags": ["hot-lead"], "created_date": "2024-09-01T10:00:00Z" } ], "pagination": { "has_more": false, "next_cursor": null } } ``` ## Error Codes | Status | Meaning | | ------ | --------------------------- | | `401` | Missing or invalid API key. | ## Example Request ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts?limit=50&sort=asc" \ -H "x-api-key: YOUR_API_KEY" ``` ### Filter by name ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts?name=jamie" \ -H "x-api-key: YOUR_API_KEY" ``` ### Paginate with a cursor ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/contacts?limit=50&cursor=NEXT_CURSOR_VALUE" \ -H "x-api-key: YOUR_API_KEY" ``` # Update a Contact — Shilo API Reference Source: https://docs.shilo.ai/api-reference/contacts/update-contact Update contact profile fields including name, phone, emails, stage, source, and tags. Use Shilo UUID or external_contact_id to identify the contact. Use this endpoint to update the profile fields of an existing contact. All body fields are optional — only the fields you include will be modified, leaving the rest unchanged. You can identify the contact by their Shilo UUID or by your external contact ID. This endpoint requires a **write-enabled** API key. ## Endpoint ``` PUT https://api.shilo.ai/api/v1/contacts/{identifier} ``` ## Authentication Include your write-enabled API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the contact. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External contact ID | `external_contact_id:4534` | ## Request Body All fields are optional. Submit only the fields you want to update. Updated full display name for the contact. Updated first name. Updated last name. Updated primary phone number. Any standard formatting is accepted. Updated list of email addresses. This replaces the existing emails array in full. Updated human-readable pipeline stage label. Updated pipeline stage ID from your system. Updated human-readable lead source label. Updated lead source ID from your system. Updated list of tags. This replaces the existing tags array in full. ## Response A successful request returns HTTP `200` with the full updated Contact object. ### Response Fields The Shilo-assigned UUID for this contact. The contact ID from your external CRM or system of record. Full display name of the contact. Contact's first name. Contact's last name. Primary phone number. Email addresses associated with the contact. Current pipeline stage label. Pipeline stage ID from your system. Lead source label. Lead source ID from your system. Tags applied to the contact. ISO-8601 timestamp indicating when this contact was created in Shilo. ### Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_contact_id": "4534", "name": "Jamie Customer", "first_name": "Jamie", "last_name": "Customer", "phone": "(555) 555-0000", "emails": ["jamie.new@example.com"], "stage": "Closed Won", "stage_id": "stage-12", "source": "Zillow", "source_id": "src-7", "tags": ["closed", "q4"], "created_date": "2024-09-01T10:00:00Z" } ``` ## Error Codes | Status | Meaning | | ------ | ----------------------------------------------------------- | | `400` | Invalid request body or malformed identifier. | | `403` | Your API key is read-only. A write-enabled key is required. | ## Example Request ```bash theme={null} curl -X PUT "https://api.shilo.ai/api/v1/contacts/external_contact_id:4534" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "phone": "(555) 555-0000", "emails": ["jamie.new@example.com"], "stage": "Closed Won", "stage_id": "stage-12", "tags": ["closed", "q4"] }' ``` # Cancel a Pending Invitation — Shilo Invitations API Source: https://docs.shilo.ai/api-reference/invitations/cancel-invitation Cancel a pending invitation in Shilo so it can no longer be accepted. Returns 204 No Content on success. Requires a write-enabled API key. Use this endpoint to cancel a pending invitation, preventing the recipient from using it to join your Shilo organization. This is useful when an agent should no longer be onboarded, or when you need to re-invite them with different details — for example, a corrected email address or a different `external_user_id`. ## Endpoint ``` DELETE https://api.shilo.ai/api/v1/invitations/{id} ``` ## Authentication This endpoint requires a **write-enabled** API key: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The unique identifier (UUID) of the invitation to cancel. You can obtain this from the [List Invitations](/api-reference/invitations/list-invitations) or [Create Invitation](/api-reference/invitations/create-invitation) endpoints. ## Response ### 204 — No Content The invitation was successfully cancelled. No response body is returned. ### 403 — Forbidden Your API key does not have write permissions. ### 404 — Not Found No invitation with the given `id` exists in your organization. ## Example Request ```bash theme={null} curl --request DELETE \ --url "https://api.shilo.ai/api/v1/invitations/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ --header "x-api-key: YOUR_API_KEY" ``` A successful cancellation returns HTTP `204 No Content` with an empty response body. # Create and Send a New Agent Invitation in Shilo API Source: https://docs.shilo.ai/api-reference/invitations/create-invitation Invite an agent to join your Shilo organization by email. Returns 201 when a new invitation is created, or 200 if a pending one exists. Use this endpoint to programmatically invite agents to join your Shilo organization. A successful `201` response indicates the invitation was created and its workflow was queued; it does not confirm that the invitation email has been delivered. Provide your own system's user identifier and, optionally, a role at invite time to maintain consistent identity mapping from day one. ## Endpoint ```text theme={null} POST https://api.shilo.ai/api/v1/invitations ``` ## Authentication This endpoint requires a **write-enabled** API key: ```text theme={null} x-api-key: YOUR_API_KEY ``` ## Request Body Send a `CreateInvitationDto` JSON object in the request body. The email address to invite. The invitation workflow will target this address. Your system's unique identifier for this user. Stored alongside the Shilo user record for cross-system identity mapping. Shilo UUID of the user sending the invitation. Exactly one of `invited_by_user_id` or `invited_by_email` is required. Email address of the user sending the invitation. Exactly one of `invited_by_user_id` or `invited_by_email` is required. Display name for the agent. Used to personalize the invitation email and pre-populate the agent's profile. Optional first name for the agent. Role to assign to the user upon accepting the invitation. Must be `ADMIN` or `MEMBER`. Defaults to `MEMBER`. ## Response ### 201 — Created A new invitation was created and the invitation workflow was queued. Returns the created Invitation object. Unique identifier for the new invitation (UUID). Recipient email address for the invitation. Your system's identifier for the invited user. Display name for the invited agent. May be `null` when not provided. First name for the invited agent. May be `null` when not provided. Role assigned on the invitation. `ADMIN` or `MEMBER`. Invitation status. Will be `PENDING` immediately after creation. ISO-8601 timestamp of when the invitation was created. ISO-8601 timestamp indicating when this invitation expires. Shilo UUID of the user who created the invitation. Shareable link the recipient can use to accept the invitation. ### 200 — Already Exists A pending invitation for this email address already exists. The existing Invitation object is returned. **No new email is sent.** Use the [Resend Invitation](/api-reference/invitations/resend-invitation) endpoint if you need to re-trigger the email. ### 400 — Bad Request The request body is missing required fields or contains invalid values. ### 403 — Forbidden Your API key does not have write permissions. ### 409 — Conflict A pending invitation for this email already exists but was created with a different `external_user_id`. Resolve the conflict before retrying. ## Example Request ```bash theme={null} curl --request POST \ --url "https://api.shilo.ai/api/v1/invitations" \ --header "x-api-key: YOUR_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "email": "newagent@example.com", "external_user_id": "usr_abc123", "name": "Jordan Smith", "first_name": "Jordan", "role": "MEMBER", "invited_by_email": "manager@example.com" }' ``` ## Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "email": "newagent@example.com", "external_user_id": "usr_abc123", "name": "Jordan Smith", "first_name": "Jordan", "role": "MEMBER", "status": "PENDING", "created_date": "2030-09-24T12:34:56Z", "expires_date": "2030-10-08T12:34:56Z", "invited_by_user_id": "b1f0a4c2-2d3e-4a10-9c66-27c1a8b7f004", "invitation_link": "https://app.shilo.ai/invitations/ee6f2136-b94a-4438-9335-3acf5b2a0d31/accept" } ``` If you receive a **200** response, the existing invitation was returned and no new email was queued. Use the [Resend Invitation](/api-reference/invitations/resend-invitation) endpoint to re-trigger the invitation email. # List Pending Invitations in Your Shilo Organization Source: https://docs.shilo.ai/api-reference/invitations/list-invitations Retrieve a paginated list of pending invitations in your Shilo organization. Supports cursor-based pagination and ascending or descending sort order. Use this endpoint to fetch all pending invitations in your Shilo organization. This is useful for auditing who has been invited but hasn't yet accepted, or for building dashboards that surface outstanding onboarding actions for your team administrators. ## Endpoint ``` GET https://api.shilo.ai/api/v1/invitations ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Query Parameters Maximum number of results to return per page. Maximum value is `100`. Pagination cursor returned from a previous response's `pagination.next_cursor`. Omit to start from the beginning of the list. Sort order for results by creation date. Accepted values: `asc`, `desc`. ## Response ### 200 — Success Returns an `InvitationsResponseDto` object containing a `data` array of Invitation objects and a `pagination` block. Array of pending Invitation objects. Unique identifier for the invitation (UUID). Email address the invitation was sent to. Current status of the invitation. Will be `pending` for all results returned by this endpoint. ISO-8601 timestamp of when the invitation was created. Pagination metadata for iterating through large result sets. Whether additional pages of results exist beyond the current page. Cursor to pass as the `cursor` query parameter to retrieve the next page. `null` when `has_more` is `false`. ### 401 — Unauthorized Your API key is missing or invalid. Ensure the `x-api-key` header is present and correct. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/invitations?limit=50&sort=asc" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "email": "newagent@example.com", "status": "pending", "created_date": "2030-09-24T12:34:56Z" } ], "pagination": { "has_more": false, "next_cursor": null } } ``` # Resend a Pending Agent Invitation Email in Shilo API Source: https://docs.shilo.ai/api-reference/invitations/resend-invitation Re-queue a pending invitation email to an agent in Shilo. Returns 202 when accepted. The invitation must still be in pending status. Use this endpoint to re-queue a pending invitation email for delivery. This is useful when an agent reports not receiving the original invitation, or when you want to follow up on an outstanding invite. The invitation must still have a `pending` status — already-accepted or cancelled invitations cannot be resent. ## Endpoint ``` POST https://api.shilo.ai/api/v1/invitations/{id}/resend ``` ## Authentication This endpoint requires a **write-enabled** API key: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The unique identifier (UUID) of the invitation to resend. You can obtain this from the [List Invitations](/api-reference/invitations/list-invitations) or [Create Invitation](/api-reference/invitations/create-invitation) endpoints. ## Response ### 202 — Accepted The resend has been queued for delivery. Returns the Invitation object. Unique identifier for the invitation (UUID). Email address the invitation will be resent to. Invitation status. Will be `pending`. ISO-8601 timestamp of the original invitation creation. ### 400 — Bad Request The request is invalid. Check that the invitation ID is correctly formatted. ### 403 — Forbidden Your API key does not have write permissions. ### 404 — Not Found No invitation with the given `id` exists in your organization. ## Example Request ```bash theme={null} curl --request POST \ --url "https://api.shilo.ai/api/v1/invitations/ee6f2136-b94a-4438-9335-3acf5b2a0d31/resend" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "email": "newagent@example.com", "status": "pending", "created_date": "2030-09-24T12:34:56Z" } ``` # Retrieve Per-Contact Call Performance Metrics — Shilo Source: https://docs.shilo.ai/api-reference/metrics/get-contact-metrics Retrieve dashboard-aligned call metrics for a single contact. Identify by Shilo UUID or external_contact_id. Filter by date and direction. Use this endpoint to retrieve call performance metrics scoped to a single contact record in Shilo. This is particularly useful for understanding the full engagement history for a lead or client — including how many calls have been made, average call quality, and total time spent. You can identify the contact using their Shilo UUID or your own `external_contact_id`. ## Endpoint ``` GET https://api.shilo.ai/api/v1/contacts/{identifier}/metrics ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters Identifies the contact to retrieve metrics for. Accepted formats: * `id:{uuid}` — prefixed Shilo UUID (e.g. `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `external_contact_id:{string}` — your CRM or system's contact ID (e.g. `external_contact_id:contact_xyz789`) * `{uuid}` — bare Shilo UUID (e.g. `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) ## Query Parameters Inclusive lower date bound as an ISO date or date-time. Date-only values use UTC start of day. Defaults to UTC start of day 29 days ago. Example: `2026-03-26T00:00:00Z`. Inclusive upper date bound as an ISO date or date-time. Date-only values use UTC end of day. Defaults to the request time. Example: `2026-04-24T18:30:00Z`. Comma-separated list of source IDs to filter by. Example: `source-1,source-2`. Comma-separated list of pipeline stage IDs to filter by. Example: `stage-1,stage-2`. Comma-separated list of team IDs to filter by. Example: `team-1,team-2`. Filter by call direction. Accepted values: `all`, `inbound`, `outbound`. ## Response ### 200 — Success Returns a `Metrics` object with aggregated performance data for the specified contact. The fields mirror the calculations shown in the contact-level insights view in the Shilo web app. ### 400 — Bad Request One or more query parameters are invalid, or the `identifier` format is not recognized. ### 401 — Unauthorized Your API key is missing or invalid. ### 404 — Not Found No contact matching the provided `identifier` was found in your organization. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/contacts/external_contact_id:contact_xyz789/metrics?date_gte=2026-03-26T00:00:00Z&type=inbound" \ --header "x-api-key: YOUR_API_KEY" ``` # Retrieve Integration-Wide Call Metrics — Shilo API Source: https://docs.shilo.ai/api-reference/metrics/get-integration-metrics Retrieve aggregated call performance metrics for your entire Shilo integration. Filter by date range, source, stage, team, and call direction. Use this endpoint to retrieve rolled-up call performance metrics across your entire Shilo integration. The data returned matches what you see in the team-level insights view in the Shilo web app, making it straightforward to embed organization-wide KPIs in your own dashboards or reporting tools. Filter results by date range, call source, pipeline stage, team, and call direction. ## Endpoint ``` GET https://api.shilo.ai/api/v1/integration/metrics ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Query Parameters Inclusive lower date bound as an ISO date or date-time. Date-only values use UTC start of day. Defaults to UTC start of day 29 days ago. Example: `2026-03-26T00:00:00Z`. Inclusive upper date bound as an ISO date or date-time. Date-only values use UTC end of day. Defaults to the request time. Example: `2026-04-24T18:30:00Z`. Comma-separated list of source IDs to filter by. Example: `source-1,source-2`. Comma-separated list of pipeline stage IDs to filter by. Example: `stage-1,stage-2`. Comma-separated list of team IDs to filter by. Example: `team-1,team-2`. Filter by call direction. Accepted values: `all`, `inbound`, `outbound`. ## Response ### 200 — Success Returns a `Metrics` object containing aggregated call performance data for the requested date window and filters. The fields mirror the calculations shown in the Shilo web app insights view. ### 400 — Bad Request One or more query parameters are invalid. Check that date values are valid ISO-8601 strings and that `type` is one of `all`, `inbound`, or `outbound`. ### 401 — Unauthorized Your API key is missing or invalid. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/integration/metrics?date_gte=2026-03-26T00:00:00Z&date_lte=2026-04-24T18:30:00Z&type=outbound" \ --header "x-api-key: YOUR_API_KEY" ``` # Retrieve Per-Agent Call Performance Metrics — Shilo Source: https://docs.shilo.ai/api-reference/metrics/get-user-metrics Retrieve dashboard-aligned call metrics for a single agent. Identify by Shilo UUID or external_user_id. Filter by date and direction. Use this endpoint to retrieve call performance metrics scoped to a single agent in your Shilo organization. The data mirrors what appears in the per-agent insights view in the Shilo web app. You can identify the agent using their Shilo UUID, a prefixed UUID, or your own `external_user_id`, giving you flexibility when querying from your CRM or other internal systems. ## Endpoint ``` GET https://api.shilo.ai/api/v1/users/{identifier}/metrics ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters Identifies the agent to retrieve metrics for. Accepted formats: * `id:{uuid}` — prefixed Shilo UUID (e.g. `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `external_user_id:{string}` — your system's user ID (e.g. `external_user_id:usr_abc123`) * `{uuid}` — bare Shilo UUID (e.g. `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) ## Query Parameters Inclusive lower date bound as an ISO date or date-time. Date-only values use UTC start of day. Defaults to UTC start of day 29 days ago. Example: `2026-03-26T00:00:00Z`. Inclusive upper date bound as an ISO date or date-time. Date-only values use UTC end of day. Defaults to the request time. Example: `2026-04-24T18:30:00Z`. Comma-separated list of source IDs to filter by. Example: `source-1,source-2`. Comma-separated list of pipeline stage IDs to filter by. Example: `stage-1,stage-2`. Comma-separated list of team IDs to filter by. Example: `team-1,team-2`. Filter by call direction. Accepted values: `all`, `inbound`, `outbound`. ## Response ### 200 — Success Returns a `Metrics` object with aggregated performance data for the specified agent. The fields mirror the calculations shown in the per-agent insights view in the Shilo web app. ### 400 — Bad Request One or more query parameters are invalid, or the `identifier` format is not recognized. ### 401 — Unauthorized Your API key is missing or invalid. ### 404 — Not Found No user matching the provided `identifier` was found in your organization. ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/users/external_user_id:usr_abc123/metrics?date_gte=2026-03-26T00:00:00Z&date_lte=2026-04-24T18:30:00Z" \ --header "x-api-key: YOUR_API_KEY" ``` # Shilo API Reference: Base URL, Auth & Status Codes Source: https://docs.shilo.ai/api-reference/overview The Shilo External API is organized around REST. Covers the base URL, authentication methods, response format, and standard HTTP status codes. The Shilo External API gives you programmatic access to call recordings, AI-generated coaching and analysis, contacts, users, and more. All endpoints follow REST conventions — you interact with them using standard HTTP methods, and every response is returned as JSON. This page covers the foundational concepts you need before diving into individual endpoints. ## Base URL All API requests are made to the following base URL: ```text theme={null} https://api.shilo.ai/api/v1 ``` Every endpoint path in this reference is relative to this base. For example, the calls list endpoint is accessed at `https://api.shilo.ai/api/v1/calls`. ## Authentication The Shilo API uses API keys to authenticate requests. You must include your API key on every request using one of the two supported header formats: ```http theme={null} x-api-key: YOUR_API_KEY ``` ```http theme={null} Authorization: Bearer YOUR_API_KEY ``` Both formats are equivalent. Each API key is scoped to a single Shilo integration within your organization, so it can only access data belonging to that integration, and it carries specific read-only or read-write permissions. Keep it secret and never expose it in client-side code or public repositories. **Read-only vs. write keys** — Shilo issues both read-only and write-enabled API keys. Read-only keys may call `GET` endpoints but will receive a `403 Forbidden` response if they attempt any write operation such as `POST /calls`. Use a write-enabled key when submitting call recordings or creating resources. ## Response Format Responses that include a body use `application/json`. Successful `204 No Content` responses have no body. Successful responses that do return a body follow a consistent envelope shape for collection endpoints: ```json theme={null} { "data": [ /* array of resource objects */ ], "pagination": { "has_more": true, "next_cursor": "eyJjcmV..." } } ``` Single-resource endpoints return the resource object directly, without a wrapping envelope. ## HTTP Status Codes Shilo uses standard HTTP status codes to indicate the outcome of every request. | Code | Meaning | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `200 OK` | The request succeeded and the response body contains the requested resource or collection. | | `201 Created` | A new resource was successfully created. The response body contains the created object. | | `202 Accepted` | The request was accepted for asynchronous processing (e.g., a new call submitted for AI analysis). | | `204 No Content` | The request succeeded and there is no response body (common for deletions). | | `400 Bad Request` | The request was malformed or contained invalid parameters. Check the response body for details. | | `401 Unauthorized` | No API key was provided, or the key is invalid or expired. | | `403 Forbidden` | Your API key does not have permission to perform this action (e.g., a read-only key on a write endpoint, or an unsupported CRM integration). | | `404 Not Found` | The requested resource does not exist. | | `409 Conflict` | The request conflicts with the current state of a resource (e.g., transcript not yet ready). | | `500 Internal Server Error` | An unexpected error occurred on Shilo's servers. Retry with exponential back-off. | ## Example Request and Response The following example retrieves your most recent call recording: ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/calls?limit=1&sort=desc" \ --header "x-api-key: YOUR_API_KEY" ``` ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "type": "call", "created_date": "2030-09-24T12:34:56Z", "duration": 120, "external_user_id": "432", "user_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "source": "Broker", "stage": "Agents" } ], "pagination": { "has_more": false, "next_cursor": null } } ``` ## API Resources The Shilo API is organized into the following resource groups. Select a section to explore the available endpoints. List, submit, retrieve, and analyze call recordings with full AI coaching output. Manage scheduled appointments tied to contacts and sales stages. Access AI-powered roleplay sessions used for agent practice and scoring. Create and manage contacts (leads) associated with your calls and appointments. Manage agent user accounts, roles, and external ID mappings. Send and track invitations for new agents to join your Shilo organization. Query aggregated performance metrics for agents and teams over time. Retrieve AI-generated coaching insights, improvement areas, and top moments. # Retrieve a Roleplay Training Call — Shilo API Source: https://docs.shilo.ai/api-reference/roleplays/get-roleplay Retrieve a single processed roleplay call by its Shilo UUID or call event ID. Returns the Roleplay object with scenario metadata, user, contact, and recording details. Use this endpoint to fetch a single roleplay training call by its identifier. You can look up a roleplay using either the Shilo-generated UUID or the call event ID associated with the session. This is useful for confirming that a roleplay has been processed or for retrieving its metadata before fetching analysis or transcript data. ## Endpoint ``` GET https://api.shilo.ai/api/v1/roleplays/{identifier} ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Path Parameters The unique identifier for the roleplay. Two formats are accepted: * `{uuid}` — The Shilo roleplay UUID (e.g., `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `call_event_id:{uuid}` — The Shilo Call Event UUID associated with this roleplay session (e.g., `call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31`) ## Response A successful request returns HTTP `200` with the matching Roleplay object. The Shilo UUID for this roleplay record. Always `"roleplay"` for records returned by this endpoint. The ISO-8601 timestamp indicating when this roleplay was created in Shilo. The duration of the roleplay call in seconds. `null` if not yet available. The Shilo UUID of the agent who completed this roleplay. `null` if no user is matched. The external user ID for the agent, as provided by your integration. `null` if not provided. The Shilo UUID of the contact associated with this roleplay. `null` if no contact is matched. The external contact ID for the associated contact, as provided by your integration. `null` if not provided. ### Error Responses | Status | Description | | ----------------- | --------------------------------------------------------------------------- | | `400 Bad Request` | The `identifier` path parameter is malformed or uses an unsupported format. | | `404 Not Found` | No roleplay was found matching the provided identifier. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/roleplays/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ --header "x-api-key: YOUR_API_KEY" ``` By call event ID: ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/roleplays/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "type": "roleplay", "created_date": "2030-09-24T12:34:56Z", "duration": 300, "external_user_id": "agent-1", "user_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "contact_id": null, "external_contact_id": null } ``` # Retrieve Roleplay Analysis — Shilo API Source: https://docs.shilo.ai/api-reference/roleplays/get-roleplay-analysis Retrieve AI analysis for a roleplay training call including coaching feedback, performance rating, disposition, objections, and session summary. Poll progress until it reaches 100. Use this endpoint to retrieve the AI-generated analysis for a roleplay training call. After each roleplay session, Shilo processes the recording asynchronously to produce detailed coaching feedback, a performance rating, objection and disposition analysis, speaker identification, and a session summary. Because processing takes time, you should poll this endpoint and check the `progress` field — all result fields are only fully populated once `progress` reaches `100`. ## Endpoint ``` GET https://api.shilo.ai/api/v1/roleplays/{identifier}/analysis ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Path Parameters The unique identifier for the roleplay. Two formats are accepted: * `{uuid}` — The Shilo roleplay UUID (e.g., `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `call_event_id:{uuid}` — The Shilo Call Event UUID associated with this roleplay session (e.g., `call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31`) ## Response A successful request returns HTTP `200` with a `RecordingAnalysis` object. The top-level fields `id`, `recording_id`, `created_at`, and `progress` are always present. All sub-resource fields (`coaching`, `rating`, `summary`, etc.) are optional and only fully populated once `progress` equals `100`. The UUID of this analysis record. The Shilo UUID of the roleplay this analysis belongs to. The ISO-8601 timestamp indicating when this analysis was created. A value between `0` and `100` representing how far along the AI processing pipeline this roleplay is. Poll this endpoint until `progress` equals `100` before reading any result fields. Recommended follow-up actions identified by the AI. Present only after processing completes. The UUID of this action items record. The most important practice or follow-up actions for the agent. Additional, lower-priority practice actions. AI-generated coaching feedback for the agent on this roleplay session. Present only after processing completes. The UUID of this coaching record. Areas where the agent could improve, with specific, actionable suggestions. Highlights from the session where the agent performed particularly well. The AI-assessed outcome and reasoning for this roleplay session. Present only after processing completes. The UUID of this disposition record. The determined outcome labels for the session (e.g., appointment set, not interested). A plain-language explanation of why the AI assigned these outcomes. Objections raised by the AI-simulated lead during the roleplay. Present only after processing completes. The UUID of this objections record. A list of objections identified in the conversation. A numeric quality rating assigned to the agent's performance on this roleplay. Present only after processing completes. The UUID of this rating record. The numeric rating score assigned to the agent's performance. A plain-language explanation of what drove the assigned score. AI-resolved speaker identities for the roleplay recording. Present only after processing completes. The UUID of this speakers record. The resolved name of the agent in this recording. The resolved name of the AI-simulated lead in this recording. A concise AI-generated summary of the roleplay session. Present only after processing completes. The UUID of this summary record. An object containing the summary text. The full text of the AI-generated roleplay session summary. Poll this endpoint until `progress` equals `100` before reading result fields such as `coaching`, `rating`, or `summary`. Sub-resource fields are absent or incomplete until processing finishes. ### Error Responses | Status | Description | | ----------------- | --------------------------------------------------------------------------- | | `400 Bad Request` | The `identifier` path parameter is malformed or uses an unsupported format. | | `404 Not Found` | No roleplay was found matching the provided identifier. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/roleplays/ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "id": "b2c3d4e5-0000-4000-8000-111122223333", "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "created_at": "2030-09-24T12:40:00Z", "progress": 100, "action_items": { "id": "b2c3d4e5-0000-4000-8000-aaaaaaaaaaaa", "primary": [ "Practice transitioning from discovery to pitch more smoothly", "Review objection-handling scripts for price resistance" ], "secondary": [ "Work on pacing — slow down during value proposition delivery" ] }, "coaching": { "id": "b2c3d4e5-0000-4000-8000-bbbbbbbbbbbb", "possible_improvements": [ "Ask more clarifying questions before presenting the offer", "Avoid interrupting the lead during objection statements" ], "top_moments": [ "Strong opening hook that captured interest immediately", "Effective use of social proof when handling the trust objection" ] }, "disposition": { "id": "b2c3d4e5-0000-4000-8000-cccccccccccc", "outcomes": ["appointment_set"], "reasoning": "The agent successfully navigated the lead's hesitation and secured a commitment for a follow-up meeting." }, "objections": { "id": "b2c3d4e5-0000-4000-8000-dddddddddddd", "outcomes": [ "Not the right time", "Already working with a competitor" ] }, "rating": { "id": "b2c3d4e5-0000-4000-8000-eeeeeeeeeeee", "outcome": 76, "reasoning": "The agent showed strong closing instincts but needs to develop more deliberate discovery questioning before moving to the pitch." }, "speakers": { "id": "b2c3d4e5-0000-4000-8000-ffffffffffff", "user_name": "Taylor Morgan", "client_name": "AI Lead" }, "summary": { "id": "b2c3d4e5-0000-4000-8000-000000000000", "outcome": { "summary": "Taylor practiced a cold outreach scenario against an AI-simulated lead who raised timing and competitive objections. Taylor overcame both and secured a mock appointment, though the session highlighted an opportunity to invest more time in early-stage discovery before transitioning to the pitch." } } } ``` # Retrieve Roleplay Transcript — Shilo API Source: https://docs.shilo.ai/api-reference/roleplays/get-roleplay-transcript Retrieve the sanitized transcript for a roleplay call with AI-resolved speaker names. Available for all CRM integrations. Returns 409 Conflict until speaker resolution is complete. Use this endpoint to retrieve the full transcript for a roleplay training call. Shilo sanitizes the raw recording transcript and applies AI-resolved speaker labels so that each segment is clearly attributed to the agent or the AI-simulated lead. Unlike transcripts for standard calls and appointments, roleplay transcripts are available regardless of your CRM integration — there is no Follow Up Boss restriction. Because speaker resolution depends on completed analysis, you should wait until the roleplay's `analysis.progress` field reaches `100` before requesting the transcript, or be prepared to handle a `409` response and retry. ## Endpoint ``` GET https://api.shilo.ai/api/v1/roleplays/{identifier}/transcript ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Path Parameters The unique identifier for the roleplay. Two formats are accepted: * `{uuid}` — The Shilo roleplay UUID (e.g., `ee6f2136-b94a-4438-9335-3acf5b2a0d31`) * `call_event_id:{uuid}` — The Shilo Call Event UUID associated with this roleplay session (e.g., `call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31`) ## Response A successful request returns HTTP `200` with a transcript object. The exact shape of the transcript object may vary, but will include speaker-attributed text segments with timing information. Roleplay transcripts are supported for all accounts regardless of CRM integration — unlike call and appointment transcripts, there is no Follow Up Boss restriction. The transcript response shape may vary. The example below shows a representative structure. Always treat the transcript as a free-form JSON object (`additionalProperties: true` in the OpenAPI spec). Fetch the transcript only after `analysis.progress` equals `100`. If speaker resolution is still in progress, the API returns `409 Conflict` — wait and retry. ### Error Responses | Status | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | The `identifier` path parameter is malformed or uses an unsupported format. | | `404 Not Found` | No roleplay was found matching the provided identifier. | | `409 Conflict` | The transcript is not yet ready. Analysis and speaker resolution are still in progress. Retry after `analysis.progress` reaches `100`. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/roleplays/ee6f2136-b94a-4438-9335-3acf5b2a0d31/transcript" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "segments": [ { "speaker": "Taylor Morgan", "text": "Hi, is this a good time? I'm reaching out because I noticed your team has been growing quickly and I think we can help you with your outreach process.", "start": 0.0, "end": 9.2 }, { "speaker": "AI Lead", "text": "We're actually already working with someone for that. I'm not sure we need another solution right now.", "start": 9.5, "end": 15.8 }, { "speaker": "Taylor Morgan", "text": "I completely understand — a lot of the teams we work with were in the same position. What I'd love to do is just share what makes us different and let you decide if it's worth a 20-minute conversation.", "start": 16.1, "end": 26.4 }, { "speaker": "AI Lead", "text": "Alright, I can spare 20 minutes. What day works for you?", "start": 26.7, "end": 31.0 } ] } ``` # List Roleplay Training Calls — Shilo API Source: https://docs.shilo.ai/api-reference/roleplays/list-roleplays Retrieve a paginated list of AI roleplay training calls. Filter by user, contact, stage, or source. Each roleplay includes scenario metadata and is separate from live call recordings. Use this endpoint to retrieve a paginated list of roleplay training calls from your Shilo account. Roleplays are practice sessions where your agents interact with AI-simulated leads to sharpen their sales skills. You can filter results by user, contact, scenario stage, or source, and navigate large result sets with cursor-based pagination. Roleplays are returned separately from standard call recordings — use the `/api/v1/calls` endpoint for non-roleplay recordings. ## Endpoint ``` GET https://api.shilo.ai/api/v1/roleplays ``` ## Authentication All requests require your API key in the `x-api-key` header. ## Query Parameters The maximum number of roleplay records to return per page. Accepted values are between `1` and `100`. An opaque pagination cursor returned in the previous response's `pagination.next_cursor` field. Pass this value to retrieve the next page of results. Omit to start from the beginning. The sort order for results, based on `created_date`. Accepted values are `asc` (oldest first) or `desc` (newest first). Return only roleplays created on or after this date and time. Must be an ISO-8601 formatted string (e.g., `2030-01-01T00:00:00Z`). Return only roleplays created on or before this date and time. Must be an ISO-8601 formatted string (e.g., `2030-12-31T23:59:59Z`). Filter roleplays by the source they were generated from. Filter roleplays by the associated agent. Accepts a prefix-qualified identifier in one of three formats: * `id:{uuid}` — Shilo user UUID * `external_user_id:{value}` — your external user ID * `{uuid}` — bare Shilo user UUID (shorthand) Filter roleplays by the associated contact. Accepts a prefix-qualified identifier in one of three formats: * `id:{uuid}` — Shilo contact UUID * `external_contact_id:{value}` — your external contact ID * `{uuid}` — bare Shilo contact UUID (shorthand) Filter roleplays by the pipeline stage associated with the scenario (e.g., prospecting, discovery, closing). ## Response A successful request returns HTTP `200` with a `RoleplaysResponseDto` object. An array of Roleplay objects matching the query filters. The Shilo UUID for this roleplay record. Always `"roleplay"` for records returned by this endpoint. The ISO-8601 timestamp indicating when this roleplay was created in Shilo. The duration of the roleplay call in seconds. `null` if not yet available. The Shilo UUID of the agent who completed this roleplay. `null` if no user is matched. The external user ID for the agent, as provided by your integration. `null` if not provided. The Shilo UUID of the contact associated with this roleplay. `null` if no contact is matched. The external contact ID for the associated contact, as provided by your integration. `null` if not provided. Metadata for paginating through additional results. `true` if there are additional pages of results beyond the current response; `false` if this is the last page. An opaque cursor string to pass as the `cursor` query parameter in your next request. Returns `null` when there are no further pages. Roleplays are returned separately from regular call recordings. Use the `/api/v1/calls` endpoint to list non-roleplay call recordings. ### Error Responses | Status | Description | | ------------------ | -------------------------------------- | | `401 Unauthorized` | Missing or invalid `x-api-key` header. | ## Example Request ```bash theme={null} curl --request GET \ --url "https://api.shilo.ai/api/v1/roleplays?limit=50&sort=desc" \ --header "x-api-key: YOUR_API_KEY" ``` ## Example Response ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "type": "roleplay", "created_date": "2030-09-24T12:34:56Z", "duration": 300, "external_user_id": "agent-1", "user_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "contact_id": null, "external_contact_id": null } ], "pagination": { "has_more": false, "next_cursor": null } } ``` # Get a User — Shilo API Reference Source: https://docs.shilo.ai/api-reference/users/get-user Retrieve a single user by Shilo UUID or your external user ID. Supports id:uuid and external_user_id: prefix patterns for flexible cross-system lookup. Use this endpoint to retrieve a single user (agent) record from your Shilo organization. You can identify the user with their Shilo UUID, a prefixed UUID, or your own external user ID — whatever aligns with your integration's data model. This flexibility means you never need to maintain a separate mapping table between your system and Shilo to look up agents. ## Endpoint ``` GET https://api.shilo.ai/api/v1/users/{identifier} ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the user. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External user ID | `external_user_id:agent-1` | ## Response A successful request returns HTTP `200` with a User object. ### Response Fields The Shilo-assigned UUID for this user. The user ID from your external system. Full display name of the user. Primary email address of the user. The user's configured timezone in IANA format (e.g. `America/New_York`). URL of the user's profile picture, if set. ISO-8601 timestamp indicating when this user was created in Shilo. ### Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_user_id": "agent-1", "name": "Alex User", "email": "alex@example.com", "timezone": "America/New_York", "picture": "https://cdn.shilo.ai/avatars/ee6f2136.png", "created_date": "2024-01-15T09:00:00Z" } ``` ## Error Codes | Status | Meaning | | ------ | --------------------------------------------------- | | `400` | The identifier format is invalid or malformed. | | `404` | No user was found matching the provided identifier. | ## Example Requests ### Look up by plain Shilo UUID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ -H "x-api-key: YOUR_API_KEY" ``` ### Look up by prefixed Shilo UUID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/id:ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ -H "x-api-key: YOUR_API_KEY" ``` ### Look up by external user ID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/external_user_id:agent-1" \ -H "x-api-key: YOUR_API_KEY" ``` # Get User Metrics — Shilo API Reference Source: https://docs.shilo.ai/api-reference/users/get-user-metrics Retrieve dashboard-aligned performance metrics for a single agent. Filter by date range, source, stage, team, and call direction. Matches the web app view. Use this endpoint to retrieve call performance metrics for a specific agent. The data mirrors what managers and agents see in the Shilo web app's insights view, and can be scoped by date range, lead source, pipeline stage, team, and call direction. This makes it easy to embed agent-level analytics in your own reporting tools, CRM dashboards, or automated performance review processes. ## Endpoint ``` GET https://api.shilo.ai/api/v1/users/{identifier}/metrics ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the user. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External user ID | `external_user_id:agent-1` | ## Query Parameters Inclusive lower bound of the date range as an ISO date or date-time (e.g. `2024-10-01T00:00:00Z`). Date-only values use UTC start of day. Defaults to UTC start of day 29 days ago. Inclusive upper bound of the date range as an ISO date or date-time. Date-only values use UTC end of day. Defaults to the request time. Comma-separated list of source IDs to filter by (e.g. `src-1,src-2`). Returns metrics only for calls associated with the specified lead sources. Comma-separated list of stage IDs to filter by. Returns metrics only for calls where the contact was in one of the specified pipeline stages. Comma-separated list of team IDs to filter by. Useful when an agent belongs to multiple teams and you want to isolate performance for a specific one. Filter by call direction. Accepted values: `all`, `inbound`, `outbound`. ## Response A successful request returns HTTP `200` with a `Metrics` object. The `Metrics` shape is the same as returned by the integration-level and contact-level metrics endpoints, scoped to this user's activity. The `Metrics` object uses the same calculations shown in the Shilo web app's insights view. Field names and structure align with the dashboard data model. ## Error Codes | Status | Meaning | | ------ | ------------------------------------------------- | | `400` | Invalid query parameters or malformed identifier. | | `401` | Missing or invalid API key. | | `404` | No user found matching the provided identifier. | ## Example Request ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/ee6f2136-b94a-4438-9335-3acf5b2a0d31/metrics?type=outbound&date_gte=2024-10-01T00:00:00Z" \ -H "x-api-key: YOUR_API_KEY" ``` ### Filter by external user ID with a date range and call direction ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/external_user_id:agent-1/metrics?date_gte=2024-10-01T00:00:00Z&date_lte=2024-10-31T23:59:59Z&type=outbound" \ -H "x-api-key: YOUR_API_KEY" ``` ### Filter by team ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/external_user_id:agent-1/metrics?team=team-101,team-202&type=all" \ -H "x-api-key: YOUR_API_KEY" ``` # Get User Signal — Shilo API Reference Source: https://docs.shilo.ai/api-reference/users/get-user-signal Retrieve the latest AI-derived behavioral and communication profile for a user, including DISC dimensions and coaching-oriented context. Use this endpoint to fetch the latest Shilo Signal for a specific agent. A Shilo Signal is the latest AI-derived behavioral and communication profile for the user, distilled from their call activity. Use it to inform coaching conversations, prepare for one-on-ones, and adapt how you communicate with the agent. ## Endpoint ```text theme={null} GET https://api.shilo.ai/api/v1/users/{identifier}/signal ``` ## Authentication Include your API key in the request header: ```text theme={null} x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the user. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External user ID | `external_user_id:agent-1` | ## Response A successful request returns HTTP `200` with a `UserSignal` object describing the agent's latest behavioral and communication profile. The `UserSignal` object contains the following required fields: * `user_id`: the Shilo UUID for the user. * `external_user_id`: your system's user ID. * `id`, `name`, `aboutMe`, `reasoning`, `conflictStyle`, `coreMotivators`, `socialOrientation`, `fearsAndAvoidances`, `maxPerformanceRecs`, and `psychologicalSummary`. * `DISC`: a required object containing the following required fields: * `dominance` * `influence` * `steadiness` * `conscientiousness` * `profileName` * `profileType` The profile fields above are present on a successful response. ## Error Codes | Status | Meaning | | ------ | -------------------------------------------------------------------------- | | `400` | Invalid or malformed identifier. | | `404` | No user found matching the provided identifier. | | `500` | The stored signal payload for this user is invalid or could not be parsed. | ## Example Request ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/ee6f2136-b94a-4438-9335-3acf5b2a0d31/signal" \ -H "x-api-key: YOUR_API_KEY" ``` ### Look up by external user ID ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users/external_user_id:agent-1/signal" \ -H "x-api-key: YOUR_API_KEY" ``` # List Users — Shilo API Reference Source: https://docs.shilo.ai/api-reference/users/list-users Retrieve a paginated list of users in your Shilo organization. Filter by external user ID, email, or name. Returns User objects with pagination cursor. Use this endpoint to retrieve all users (agents) in your Shilo organization. Results are paginated and can be filtered by external user ID, email address, or name. Pass the `cursor` value from the pagination object into your next request to walk through large teams page by page. ## Endpoint ``` GET https://api.shilo.ai/api/v1/users ``` ## Authentication Include your API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Query Parameters Maximum number of users to return per page. Accepted range is 1–100. Pagination cursor returned by a previous response. Pass this value to retrieve the next page of results. Sort order by created date. Accepted values: `asc`, `desc`. Filter by your system's user ID. Exact match only. Filter by email address. Case-insensitive exact match. Filter by user name. Case-insensitive partial match — useful for search-as-you-type UIs. ## Response A successful request returns HTTP `200` with a `UsersResponseDto` object. ### Response Fields An array of User objects matching your query filters. The Shilo-assigned UUID for this user. The user ID from your external system. Full display name of the user. Primary email address of the user. The user's configured timezone in IANA format (e.g. `America/New_York`). URL of the user's profile picture, if set. ISO-8601 timestamp indicating when this user was created in Shilo. Pagination metadata for the current response. `true` if additional pages of results exist beyond the current page. Cursor value to pass in your next request to retrieve the following page. `null` when no further pages are available. ### Example Response ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_user_id": "agent-1", "name": "Alex User", "email": "alex@example.com", "timezone": "America/New_York", "picture": "https://cdn.shilo.ai/avatars/ee6f2136.png", "created_date": "2024-01-15T09:00:00Z" } ], "pagination": { "has_more": false, "next_cursor": null } } ``` ## Error Codes | Status | Meaning | | ------ | --------------------------- | | `401` | Missing or invalid API key. | ## Example Request ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users?limit=50&sort=asc" \ -H "x-api-key: YOUR_API_KEY" ``` ### Filter by name ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users?name=alex" \ -H "x-api-key: YOUR_API_KEY" ``` ### Paginate with a cursor ```bash theme={null} curl -X GET "https://api.shilo.ai/api/v1/users?limit=50&cursor=NEXT_CURSOR_VALUE" \ -H "x-api-key: YOUR_API_KEY" ``` # Suspend a User — Shilo API Reference Source: https://docs.shilo.ai/api-reference/users/suspend-user Suspend a user's membership in your Shilo integration. Does not delete their Shilo account or remove integration membership for Zillow Flex Advisor users. Use this endpoint to suspend a user from your Shilo integration. Suspension removes the user's access within the context of your integration but does **not** delete their underlying Shilo account or affect memberships in other integrations. Note that Zillow Flex Advisor users are outside the scope of this endpoint and will not be affected by calls made here. This endpoint requires a **write-enabled** API key. ## Endpoint ``` DELETE https://api.shilo.ai/api/v1/users/{identifier} ``` ## Authentication Include your write-enabled API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the user. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External user ID | `external_user_id:agent-1` | ## Response A successful request returns HTTP `204 No Content` with no response body. ## Important Notes This endpoint suspends the user for **your integration only**. It does not permanently delete their Shilo account, and their data — including call history and signal scores — remains intact. Zillow Flex Advisor users are not affected by this endpoint. Their integration membership cannot be removed through the API. ## Error Codes | Status | Meaning | | ------ | ----------------------------------------------------------- | | `400` | Invalid or malformed identifier. | | `403` | Your API key is read-only. A write-enabled key is required. | ## Example Request ```bash theme={null} curl -X DELETE "https://api.shilo.ai/api/v1/users/ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ -H "x-api-key: YOUR_API_KEY" ``` ### Using external user ID ```bash theme={null} curl -X DELETE "https://api.shilo.ai/api/v1/users/external_user_id:agent-1" \ -H "x-api-key: YOUR_API_KEY" ``` # Update a User — Shilo API Reference Source: https://docs.shilo.ai/api-reference/users/update-user Update a user's name, timezone, picture, or external ID in Shilo. Use the Shilo UUID or external_user_id to identify the user. Requires a write key. Use this endpoint to update an agent's profile fields in Shilo. All body fields are optional — you only need to include the fields you want to change. You can identify the user by their Shilo UUID or your external user ID. This endpoint requires a **write-enabled** API key — read-only keys will receive a `403` response. ## Endpoint ``` PUT https://api.shilo.ai/api/v1/users/{identifier} ``` ## Authentication Include your write-enabled API key in the request header: ``` x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the user. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External user ID | `external_user_id:agent-1` | ## Request Body All fields are optional. Submit only the fields you want to update. Updated full display name for the user. Updated ID from your external system. Use this to re-map a Shilo user to a new external identifier. Updated timezone for the user in IANA format (e.g. `America/Chicago`). Updated URL for the user's profile picture. ## Response A successful request returns HTTP `200` with the full updated User object. ### Response Fields The Shilo-assigned UUID for this user. The user's external system ID. Full display name of the user. Primary email address of the user. The user's configured timezone. URL of the user's profile picture. ISO-8601 timestamp indicating when this user was created in Shilo. ### Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_user_id": "agent-1", "name": "Alex User", "email": "alex@example.com", "timezone": "America/Chicago", "picture": "https://cdn.shilo.ai/avatars/ee6f2136.png", "created_date": "2024-01-15T09:00:00Z" } ``` ## Error Codes | Status | Meaning | | ------ | ----------------------------------------------------------- | | `400` | Invalid request body or malformed identifier. | | `403` | Your API key is read-only. A write-enabled key is required. | ## Example Request ```bash theme={null} curl -X PUT "https://api.shilo.ai/api/v1/users/external_user_id:agent-1" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Alex User", "timezone": "America/Chicago", "picture": "https://cdn.shilo.ai/avatars/ee6f2136.png" }' ``` # Update User Email — Shilo API Reference Source: https://docs.shilo.ai/api-reference/users/update-user-email Update the email address for a Shilo user. This dedicated endpoint is separate from the general profile update. Requires a write-enabled API key. Use this endpoint to change the email address associated with a Shilo user account. Email updates are handled through a dedicated endpoint — separate from the general profile update — because changing a user's email may trigger downstream notifications and identity-related processes within Shilo. This endpoint requires a **write-enabled** API key. ## Endpoint ```text theme={null} PUT https://api.shilo.ai/api/v1/users/{identifier}/update_email ``` ## Authentication Include your write-enabled API key in the request header: ```text theme={null} x-api-key: YOUR_API_KEY ``` ## Path Parameters The identifier used to look up the user. Three formats are supported: | Format | Example | | ------------------- | ----------------------------------------- | | Plain Shilo UUID | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | Prefixed Shilo UUID | `id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` | | External user ID | `external_user_id:agent-1` | ## Request Body The user's current email address. Used to identify the account being updated. The new email address to assign to this user. Must be a valid email format. ### Example Body ```json theme={null} { "existing_email": "alex@example.com", "updated_email": "alex.new@example.com" } ``` ## Response A successful request returns HTTP `200` with the full updated User object reflecting the new email address. ### Response Fields The Shilo-assigned UUID for this user. The user's external system ID. Full display name of the user. The updated primary email address of the user. The user's configured timezone. URL of the user's profile picture. ISO-8601 timestamp indicating when this user was created in Shilo. ### Example Response ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "external_user_id": "agent-1", "name": "Alex User", "email": "alex.new@example.com", "timezone": "America/New_York", "picture": "https://cdn.shilo.ai/avatars/ee6f2136.png", "created_date": "2024-01-15T09:00:00Z" } ``` ## Error Codes | Status | Meaning | | ------ | ------------------------------------------------------------------------------------------- | | `400` | Invalid request body, missing `existing_email` or `updated_email`, or malformed identifier. | | `403` | Your API key is read-only. A write-enabled key is required. | | `404` | No user found matching the provided identifier. | ## Example Request ```bash theme={null} curl -X PUT "https://api.shilo.ai/api/v1/users/ee6f2136-b94a-4438-9335-3acf5b2a0d31/update_email" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "existing_email": "alex@example.com", "updated_email": "alex.new@example.com" }' ``` ### Using external user ID ```bash theme={null} curl -X PUT "https://api.shilo.ai/api/v1/users/external_user_id:agent-1/update_email" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "existing_email": "alex@example.com", "updated_email": "alex.new@example.com" }' ``` # Authenticate with the Shilo API Using API Keys Source: https://docs.shilo.ai/authentication All Shilo API requests require an API key. Learn how to generate one, pass it in requests, and understand read-only vs. read-write key permissions. Every request to the Shilo API must include a valid API key. Each key is scoped to a single Shilo integration within your organization, so it can only access data belonging to that integration. Keys also carry either read-only or read-write permissions, so you can issue tightly scoped credentials to third-party tools without granting unnecessary access. ## Generating an API Key API keys are created in the Shilo web app. You must be an **owner** or **admin** to generate them. 1. Open **Settings** in the Shilo app. 2. Navigate to **API Keys**. 3. Click **Generate API Key**, give it a descriptive name, select the integration the key should be scoped to, and choose its permission level. 4. Copy the key immediately—it will not be shown again. ## Sending Your API Key You can authenticate using either of two header formats. Both are accepted on every endpoint. ### Option 1 — `x-api-key` header (recommended) ```bash theme={null} curl https://api.shilo.ai/api/v1/users \ -H "x-api-key: YOUR_API_KEY" ``` ### Option 2 — `Authorization: Bearer` header ```bash theme={null} curl https://api.shilo.ai/api/v1/users \ -H "Authorization: Bearer YOUR_API_KEY" ``` Both headers carry the same key value. Use whichever format fits your HTTP client or SDK most naturally. ## Read-Only vs. Read-Write Keys Shilo issues two permission tiers: | Key type | Allowed methods | Blocked methods | | -------------- | ------------------------------ | ----------------------- | | **Read-only** | `GET` | `POST`, `PUT`, `DELETE` | | **Read-write** | `GET`, `POST`, `PUT`, `DELETE` | — | A read-only key attempting a write operation receives a `403 Forbidden` response. This lets you safely hand a key to a reporting dashboard or analytics pipeline without risking accidental data changes. ## Error Responses | Status | Meaning | | ------------------ | ---------------------------------------------------------------- | | `401 Unauthorized` | The API key is missing from the request or is invalid. | | `403 Forbidden` | The API key is read-only and the endpoint requires write access. | A `401` response typically means the key was not included in the header, was mistyped, or has been revoked. Double-check both the header name and the key value. ## Complete Authentication Example The following request lists the users belonging to the key's integration, using the `x-api-key` header: ```bash theme={null} curl https://api.shilo.ai/api/v1/users \ -H "x-api-key: YOUR_API_KEY" ``` The same request using the `Authorization` header: ```bash theme={null} curl https://api.shilo.ai/api/v1/users \ -H "Authorization: Bearer YOUR_API_KEY" ``` Keep your API keys secret. Never embed them in client-side JavaScript, mobile app binaries, or public repositories. Store keys in environment variables or a secrets manager, and rotate them regularly to limit exposure if a key is compromised. ## Security Best Practices * **Use separate keys per integration.** Isolate credentials so you can revoke a single key without disrupting other systems. * **Prefer read-only keys** for any integration that only needs to read data. * **Rotate keys periodically.** Generate a replacement key, update your integration, then delete the old key. * **Audit key usage.** Check the Shilo Settings page regularly for keys that are no longer in use and revoke them. # Understanding AI Analysis Results from Shilo Source: https://docs.shilo.ai/concepts/analysis Learn what Shilo's AI analysis object contains, how to interpret each field, and how to poll for completion before reading results. When you submit a recording to Shilo, the AI pipeline processes it asynchronously and populates an analysis object with structured coaching data. The same analysis schema is returned for calls, appointments, and roleplays, so the concepts here apply across all three resource types. Understanding how to read and interpret the analysis object is the foundation of any Shilo integration. ## Analysis Endpoints Each recording type exposes a dedicated analysis endpoint: | Resource | Endpoint | | ------------ | ------------------------------------------------ | | Calls | `GET /api/v1/calls/{identifier}/analysis` | | Appointments | `GET /api/v1/appointments/{identifier}/analysis` | | Roleplays | `GET /api/v1/roleplays/{identifier}/analysis` | ## The `progress` Field The `progress` field is an integer from `0` to `100` that indicates how far along the AI processing pipeline the recording has advanced. Poll the analysis endpoint and check `progress` before reading any other field: * **`progress < 100`** — Processing is still in progress. Analysis sub-objects may be `null` or absent. Do not use partial results. * **`progress == 100`** — Processing is complete. Individual analysis sub-objects (`action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, and `summary`) are optional and may still be `null` or omitted, so clients must check for presence before reading each field. Store the completed analysis object in your own database after `progress` reaches `100`. This avoids repeated polling on already-processed recordings and reduces unnecessary API calls. ## Analysis Sub-Objects ### `rating` The AI's overall assessment of the call's quality or outcome. | Field | Type | Description | | ----------- | ------ | ------------------------------------------------------------ | | `outcome` | number | Numeric score representing call quality or result (e.g. `4`) | | `reasoning` | string | Human-readable explanation for the score | **Example:** ```json theme={null} { "id": "r1r1r1r1-0000-0000-0000-000000000001", "outcome": 4, "reasoning": "Great rapport and clear value proposition; discovery questions could be more open-ended." } ``` ### `summary` A concise natural-language narrative of what happened on the call. | Field | Type | Description | | ----------------- | ---------------- | ------------------------------------------------------------------------------------------------------- | | `outcome` | object \| string | Either an object (commonly `{ "summary": string }`) or a plain string. Clients must handle both shapes. | | `outcome.summary` | string | When `outcome` is an object, the human-readable summary of the conversation. | **Example (object form):** ```json theme={null} { "id": "s1s1s1s1-0000-0000-0000-000000000002", "outcome": { "summary": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday." } } ``` **Example (string form):** ```json theme={null} { "id": "s1s1s1s1-0000-0000-0000-000000000002", "outcome": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday." } ``` ### `coaching` Structured coaching feedback broken into two complementary lists. | Field | Type | Description | | ----------------------- | --------- | -------------------------------------------------------- | | `possible_improvements` | string\[] | Specific behaviors the agent can improve on future calls | | `top_moments` | string\[] | Positive highlights worth reinforcing | **Example:** ```json theme={null} { "id": "c1c1c1c1-0000-0000-0000-000000000003", "possible_improvements": [ "Ask more open-ended discovery questions before presenting price", "Acknowledge objections before pivoting to benefits" ], "top_moments": [ "Handled the timeline objection with a compelling urgency frame", "Confirmed next steps clearly at the end of the call" ] } ``` ### `disposition` The AI's classification of how the call ended or what outcome it represents. | Field | Type | Description | | ----------- | --------- | -------------------------------------------------------- | | `outcomes` | string\[] | One or more disposition labels (e.g. `"Qualified lead"`) | | `reasoning` | string | Explanation of why the call was classified this way | **Example:** ```json theme={null} { "id": "d1d1d1d1-0000-0000-0000-000000000004", "outcomes": ["Qualified lead"], "reasoning": "Prospect confirmed budget and expressed positive intent to move forward." } ``` ### `objections` Objections that the prospect raised during the conversation. | Field | Type | Description | | ---------- | --------- | ------------------------------------ | | `outcomes` | string\[] | List of identified objection strings | **Example:** ```json theme={null} { "id": "o1o1o1o1-0000-0000-0000-000000000005", "outcomes": ["Price concerns", "Needs to consult spouse"] } ``` ### `action_items` Follow-up tasks identified from the call, split into two priority tiers. | Field | Type | Description | | ----------- | --------- | ------------------------------------------------------- | | `primary` | string\[] | High-priority actions the agent should take immediately | | `secondary` | string\[] | Supporting or lower-priority follow-up tasks | **Example:** ```json theme={null} { "id": "ai1ai1a1-0000-0000-0000-000000000006", "primary": ["Schedule follow-up appointment for next Thursday"], "secondary": ["Send recap email with listing details"] } ``` ### `speakers` AI-resolved speaker identities reconciled with your user and contact data. | Field | Type | Description | | ------------- | ------ | --------------------------------------- | | `user_name` | string | Resolved name of the agent on the call | | `client_name` | string | Resolved name of the client or prospect | **Example:** ```json theme={null} { "id": "sp1sp1s1-0000-0000-0000-000000000007", "user_name": "Alex Johnson", "client_name": "Jamie Rivera" } ``` ## Complete Analysis Response Example The following payload shows what a fully populated response can look like. It is an illustrative example, not a guaranteed shape: any of `action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, and `summary` may be `null` or omitted, and `summary.outcome` may be an object or a string. ```json theme={null} { "id": "a1b2c3d4-0000-0000-0000-111122223333", "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "created_at": "2030-09-24T12:34:56Z", "progress": 100, "rating": { "id": "r1r1r1r1-0000-0000-0000-000000000001", "outcome": 4, "reasoning": "Great rapport and clear value proposition; discovery questions could be more open-ended." }, "summary": { "id": "s1s1s1s1-0000-0000-0000-000000000002", "outcome": { "summary": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday." } }, "coaching": { "id": "c1c1c1c1-0000-0000-0000-000000000003", "possible_improvements": [ "Ask more open-ended discovery questions before presenting price" ], "top_moments": [ "Confirmed next steps clearly at the end of the call" ] }, "disposition": { "id": "d1d1d1d1-0000-0000-0000-000000000004", "outcomes": ["Qualified lead"], "reasoning": "Prospect confirmed budget and expressed positive intent to move forward." }, "objections": { "id": "o1o1o1o1-0000-0000-0000-000000000005", "outcomes": ["Price concerns", "Needs to consult spouse"] }, "action_items": { "id": "ai1ai1a1-0000-0000-0000-000000000006", "primary": ["Schedule follow-up appointment for next Thursday"], "secondary": ["Send recap email with listing details"] }, "speakers": { "id": "sp1sp1s1-0000-0000-0000-000000000007", "user_name": "Alex Johnson", "client_name": "Jamie Rivera" } } ``` ## Transcripts In addition to the structured analysis object, you can retrieve the full call transcript with AI-resolved speaker names: | Resource | Endpoint | | ------------ | -------------------------------------------------- | | Calls | `GET /api/v1/calls/{identifier}/transcript` | | Appointments | `GET /api/v1/appointments/{identifier}/transcript` | | Roleplays | `GET /api/v1/roleplays/{identifier}/transcript` | A `409 Conflict` response means the transcript is not yet ready—speaker resolution must complete before the transcript is available. Poll and retry after a short wait. For Shilo accounts connected to Follow Up Boss, only the **call and appointment** transcript endpoints (`GET /api/v1/calls/{identifier}/transcript` and `GET /api/v1/appointments/{identifier}/transcript`) are unsupported and return `403 Forbidden`. The roleplay transcript endpoint, `GET /api/v1/roleplays/{identifier}/transcript`, remains supported for all integrations, including Follow Up Boss. # Identifier Patterns for Shilo API Resources Source: https://docs.shilo.ai/concepts/identifiers Shilo supports multiple identifier formats for calls, contacts, and users. Learn the prefix:value pattern and when to use each identifier type. Most Shilo API endpoints accept an `{identifier}` path parameter rather than a single fixed ID type. This flexible design lets you reference a resource using either its Shilo-generated UUID or an ID from your own system, without needing a separate lookup step first. Understanding which identifier to use—and when—keeps your integration code simple and reduces round trips. ## The `prefix:value` Pattern Identifiers that are not plain UUIDs use a `prefix:value` format. The prefix tells Shilo which ID namespace you are referencing. For example: * `call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31` — look up by call event ID * `external_recording_id:rec-001` — look up by the `recording_id` you provided at submission * `external_user_id:agent-123` — look up a user by your system's user ID * `external_contact_id:contact-456` — look up a contact by your CRM's contact ID A plain UUID without a prefix is always treated as the Shilo internal UUID for that resource. ## Identifier Reference by Resource ### Calls | Format | Example | When to use | | -------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------ | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | You already have the Shilo call UUID | | `call_event_id:{uuid}` | `call_event_id:ee6f2136-...` | Right after submitting a call; use the `call_event_id` from the `202` response | | `external_recording_id:{string}` | `external_recording_id:rec-001` | You want to look up a call by the `recording_id` you supplied at creation | ### Contacts | Format | Example | When to use | | ------------------------------ | -------------------------------------- | ------------------------------------------------ | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | You already have the Shilo contact UUID | | `id:{uuid}` | `id:ee6f2136-...` | Explicit alternative to the bare UUID format | | `external_contact_id:{string}` | `external_contact_id:contact-456` | You want to reference a contact by your CRM's ID | ### Users | Format | Example | When to use | | --------------------------- | -------------------------------------- | ----------------------------------------------------- | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | You already have the Shilo user UUID | | `id:{uuid}` | `id:ee6f2136-...` | Explicit alternative to the bare UUID format | | `external_user_id:{string}` | `external_user_id:agent-123` | You want to reference a user by your system's user ID | ### Appointments | Format | Example | When to use | | -------------------------------- | -------------------------------------- | ------------------------------------------------------ | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | You already have the Shilo recording UUID | | `external_recording_id:{string}` | `external_recording_id:appt-789` | You want to look up by the `recording_id` you provided | ### Roleplays | Format | Example | When to use | | ---------------------- | -------------------------------------- | -------------------------------------------------------------------------- | | `{uuid}` | `ee6f2136-b94a-4438-9335-3acf5b2a0d31` | You already have the Shilo roleplay UUID | | `call_event_id:{uuid}` | `call_event_id:ee6f2136-...` | Right after roleplay submission; use the `call_event_id` from the response | ## Using External IDs Throughout Your Integration Shilo's external ID support means you can submit a call using your own `recording_id` and later retrieve its analysis without ever storing Shilo's internal UUID. The same principle applies to users and contacts: pass your own IDs at call submission time, and use `external_user_id:` and `external_contact_id:` prefixes everywhere you need to look them up. ```bash theme={null} # Retrieve a call by the recording_id you chose at submission curl https://api.shilo.ai/api/v1/calls/external_recording_id:rec-001 \ -H "x-api-key: YOUR_API_KEY" # Retrieve analysis using the call_event_id from the 202 response curl https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis \ -H "x-api-key: YOUR_API_KEY" # Retrieve the same call by its Shilo UUID (once you have it) curl https://api.shilo.ai/api/v1/calls/a1b2c3d4-5678-90ab-cdef-111122223333 \ -H "x-api-key: YOUR_API_KEY" ``` Immediately after submitting a call, use `call_event_id:{uuid}` as the identifier because the Shilo call UUID may not be available yet. Once analysis completes and you have retrieved the full call object, you can switch to the stable Shilo UUID for any subsequent lookups. ## Invalid Identifier Errors If you pass an identifier in an unrecognized format, or if no resource matches the given ID, the API returns: | Status | Meaning | | ----------------- | ------------------------------------------------------- | | `400 Bad Request` | The identifier format is invalid or cannot be parsed | | `404 Not Found` | The identifier is valid but no matching resource exists | # Cursor-Based Pagination in the Shilo API Source: https://docs.shilo.ai/concepts/pagination Shilo list endpoints use cursor-based pagination. Learn how to use limit, cursor, and sort parameters to page through large result sets efficiently. All Shilo list endpoints return results in pages. Rather than offset-based pagination (which can miss or duplicate records when data changes between requests), Shilo uses a cursor-based approach that gives you a stable pointer into the result set. This makes it safe to page through large collections—like all calls for an agent over the past year—without worrying about skipped or duplicated records. ## Response Shape Every list endpoint returns a top-level `data` array and a `pagination` object: ```json theme={null} { "data": [ { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", ... }, { "id": "a1b2c3d4-5678-90ab-cdef-111122223333", ... } ], "pagination": { "has_more": true, "next_cursor": "eyJjcmVhdGVkX2RhdGUiOiIyMDMwLTA5LTI0VDEyOjM0OjU2WiIsImlkIjoiYTFiMmMzZDQifQ==" } } ``` | Field | Type | Description | | ------------------------ | -------------- | -------------------------------------------------------------------------------------- | | `data` | array | The current page of results | | `pagination.has_more` | boolean | `true` if additional results exist beyond this page | | `pagination.next_cursor` | string \| null | Opaque cursor to pass in your next request; `null` when you have reached the last page | ## Query Parameters | Parameter | Default | Maximum | Description | | --------- | ------- | ------- | ------------------------------------------------------------------- | | `limit` | `50` | `100` | Number of records to return per page | | `cursor` | — | — | Opaque cursor from the previous response's `pagination.next_cursor` | | `sort` | `asc` | — | Sort direction by created date: `asc` or `desc` | ## Fetching All Pages To retrieve every record in a collection, loop until `has_more` is `false`: ```bash theme={null} # Page 1 — no cursor needed curl "https://api.shilo.ai/api/v1/calls?limit=100&sort=asc" \ -H "x-api-key: YOUR_API_KEY" # Page 2 — pass the next_cursor from the previous response curl "https://api.shilo.ai/api/v1/calls?limit=100&sort=asc&cursor=eyJjcmVh..." \ -H "x-api-key: YOUR_API_KEY" # Continue until has_more is false ``` In pseudocode: ``` cursor = null loop: response = GET /api/v1/calls?limit=100&sort=asc[&cursor={cursor}] process(response.data) if response.pagination.has_more == false: break cursor = response.pagination.next_cursor ``` ## Last Page Indicator When you have retrieved all available records, the response looks like this: ```json theme={null} { "data": [ { "id": "last-record-uuid", ... } ], "pagination": { "has_more": false, "next_cursor": null } } ``` `has_more: false` and `next_cursor: null` together confirm you have reached the end of the result set. The cursor value is opaque—do not attempt to parse, decode, or construct it manually. Always use the exact string returned by the API in the previous response. Modifying the cursor produces a `400 Bad Request` error. ## Filtering and Sorting with Pagination Most list endpoints accept additional query parameters for filtering (e.g. `user_id`, `contact_id`, `created_date_gte`). You can combine filters with pagination—just include all parameters in every request, including cursor pages: ```bash theme={null} # Filter calls for a specific user, 100 per page, newest first curl "https://api.shilo.ai/api/v1/calls?limit=100&sort=desc&user_id=external_user_id:agent-123" \ -H "x-api-key: YOUR_API_KEY" ``` When syncing a large dataset for the first time, use `sort=asc` and `limit=100` to minimize the number of requests. For incremental syncs, use `created_date_gte` with your last sync timestamp so you only fetch new records. # Automate 1:1 Coaching Workflows with the Shilo API Source: https://docs.shilo.ai/guides/coaching-workflows Learn how Shilo's 1:1 Coaching feature works, how to retrieve settings and periods, and how to surface coaching agendas for agents. Shilo's 1:1 Coaching feature automatically generates structured coaching periods and per-agent agendas by analyzing the calls your team submits. The Coaching API gives you read-only access to your integration's coaching settings, the periods that have been generated, and the individual agent agendas within each period—so you can surface coaching prompts, track completion, and build custom reporting workflows. ## How 1:1 Coaching Works At the cadence you configure (weekly, semimonthly, or monthly), Shilo generates a new coaching period covering a window of historical call data. Within each period, Shilo creates an agenda for every eligible agent. Each agenda is a personalized coaching document the agent completes before their 1:1 meeting. After agents submit their agendas, Shilo compiles a team digest the manager can use to prepare. ## Coaching Settings Retrieve your integration's coaching configuration at any time: ```bash theme={null} curl https://api.shilo.ai/api/v1/coaching/settings \ -H "x-api-key: YOUR_API_KEY" ``` **Example response:** ```json theme={null} { "integration_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "enabled": true, "cadence": "weekly", "customization": { "focus": "Improve discovery and objection handling", "questions": [ { "id": "question-1", "order": 0, "text": "What should we practice in our next session?" } ] }, "usage_limits": { "integration_limit_seconds": 36000, "per_user_limit_seconds": 3600 } } ``` ### Key Settings Fields | Field | Description | | ------------------------- | ------------------------------------------------------------------------------------------------ | | `enabled` | Whether the 1:1 Coaching feature is toggled on for this integration, independent of usage limits | | `cadence` | How often coaching periods are generated: `weekly`, `semimonthly`, or `monthly` | | `customization.focus` | Optional text describing the current coaching focus area | | `customization.questions` | Custom questions added to every agent agenda | ### Usage Limits `integration_limit_seconds` controls the total coaching budget for the entire organization per period, and `per_user_limit_seconds` controls the budget for each individual agent. Both fields follow the same value convention: | Value | Meaning | | ---------------------- | ----------------------------------- | | `number` (e.g. `3600`) | Maximum coaching seconds allowed | | `null` | No limit — coaching is unrestricted | | `0` | Coaching is blocked entirely | For example, `integration_limit_seconds: 36000` allows up to 10 hours of coaching across all agents per period, while `per_user_limit_seconds: 0` blocks coaching for every individual agent regardless of the organization-wide limit. ## Coaching Periods A coaching period represents the time window whose call data was used to generate agendas. Each period has both a data range (`period_start` to `period_end`) and a review window (`review_period_end`) during which agents can submit their agendas. ### List Coaching Periods ```bash theme={null} curl "https://api.shilo.ai/api/v1/coaching/periods?sort=desc&limit=10" \ -H "x-api-key: YOUR_API_KEY" ``` Add the optional `cadence` filter to narrow results: ```bash theme={null} curl "https://api.shilo.ai/api/v1/coaching/periods?cadence=weekly&sort=desc" \ -H "x-api-key: YOUR_API_KEY" ``` ### Period Status Fields | Field | Values | Description | | --------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------- | | `review_status` | `open` / `closed` | `open` while agents can still submit agendas (through `review_period_end`); `closed` once the deadline passes | | `digest_status` | `pending` / `completed` | `pending` while the team digest is being compiled; `completed` when it is ready | ### Retrieve a Single Period ```bash theme={null} curl https://api.shilo.ai/api/v1/coaching/periods/PERIOD_ID \ -H "x-api-key: YOUR_API_KEY" ``` The response includes the team digest once `digest_status` is `completed`. Use this to surface the manager-facing summary of the period. **Example period object:** ```json theme={null} { "id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "cadence": "weekly", "period_start": "2026-06-01", "period_end": "2026-06-07", "review_period_end": "2026-06-14", "review_status": "open", "digest_status": "pending", "created_date": "2026-06-08T12:34:56Z", "updated_date": "2026-06-08T12:34:56Z" } ``` ## Agent Agendas Each agent eligible for a coaching period receives a personalized agenda. The Coaching API returns agenda metadata, generation and completion state, and an authenticated Shilo web deep link when available, so you can direct agents into their coaching session. The endpoints do not return the generated agenda's questions or body content. ### List Agendas for a Period ```bash theme={null} curl "https://api.shilo.ai/api/v1/coaching/periods/PERIOD_ID/agendas" \ -H "x-api-key: YOUR_API_KEY" ``` Filter by a specific user using any supported user identifier: ```bash theme={null} curl "https://api.shilo.ai/api/v1/coaching/periods/PERIOD_ID/agendas?user_id=external_user_id:agent-123" \ -H "x-api-key: YOUR_API_KEY" ``` ### Retrieve a Single Agenda ```bash theme={null} curl https://api.shilo.ai/api/v1/coaching/agendas/AGENDA_ID \ -H "x-api-key: YOUR_API_KEY" ``` ### Key Agenda Fields | Field | Description | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `agenda_url` | Authenticated Shilo web deep link to the agent's coaching session. Present only for `ready` agendas with exactly one active user mapping. Requires normal Shilo web authentication; contains no API key or login token | | `generation_status` | One of `queued`, `processing`, `ready`, `failed`, or `not_eligible` | | `is_completed` | Whether the agent has completed the agenda | | `completed_at` | ISO-8601 timestamp of completion, or `null` | | `completed_on_time` | Whether the agenda was completed before `review_period_end`, or `null` | | `analysis_ready` | Whether post-submission analysis has produced a stored summary | | `external_user_id` | Your system's user ID for the agent | | `user_id` | Shilo's internal user UUID | ## Common Workflows ### Check if Coaching is Enabled ```bash theme={null} curl https://api.shilo.ai/api/v1/coaching/settings \ -H "x-api-key: YOUR_API_KEY" # Check: enabled == true AND per_user_limit_seconds != 0 AND integration_limit_seconds != 0 ``` ### List Open Periods (Agents Can Still Submit) ```bash theme={null} curl "https://api.shilo.ai/api/v1/coaching/periods?sort=desc&limit=50" \ -H "x-api-key: YOUR_API_KEY" # Filter client-side: review_status == "open" ``` ### Get All Agendas for an Agent Across a Period ```bash theme={null} curl "https://api.shilo.ai/api/v1/coaching/periods/PERIOD_ID/agendas?user_id=external_user_id:agent-123" \ -H "x-api-key: YOUR_API_KEY" ``` ### Direct an Agent to Their Agenda Retrieve the agent's agenda and send them the `agenda_url` field when it is present: ```bash theme={null} curl https://api.shilo.ai/api/v1/coaching/agendas/AGENDA_ID \ -H "x-api-key: YOUR_API_KEY" # Use response.agenda_url to link the agent directly to their coaching agenda ``` The Coaching API is read-only. You cannot create, update, or delete coaching periods or agendas through the API—these are managed automatically by Shilo based on your configured cadence and the calls submitted to your integration. # Manage Users and Invitations Through the Shilo API Source: https://docs.shilo.ai/guides/managing-users Learn how to list, update, and suspend users, send team invitations, and sync your user data with Shilo using external IDs. Shilo users represent the agents and team members in your sales organization. The Users API lets you retrieve user records, update profile information, and suspend members who have left your team. The Invitations API handles the onboarding flow for new agents who haven't yet joined Shilo. Together, these endpoints let you keep your Shilo roster in sync with your own system of record. ## Users vs. Contacts Before diving in, it helps to distinguish the two people-related resources in Shilo: * **Users** — Your sales agents. They log in to Shilo, receive coaching agendas, and appear in performance metrics. * **Contacts** — The leads and clients your agents call. They do not log in to Shilo; they exist as subjects of call analysis. ## Listing Users Retrieve a paginated list of all users in your organization: ```bash theme={null} curl "https://api.shilo.ai/api/v1/users" \ -H "x-api-key: YOUR_API_KEY" ``` Filter the list by external ID, email, or name: ```bash theme={null} # Filter by your system's user ID curl "https://api.shilo.ai/api/v1/users?external_user_id=agent-123" \ -H "x-api-key: YOUR_API_KEY" # Filter by email (case-insensitive exact match) curl "https://api.shilo.ai/api/v1/users?email=alex%40example.com" \ -H "x-api-key: YOUR_API_KEY" # Filter by name (case-insensitive partial match) curl "https://api.shilo.ai/api/v1/users?name=alex" \ -H "x-api-key: YOUR_API_KEY" ``` ## Retrieving a Single User Use any of the three supported identifier formats: ```bash theme={null} # By Shilo UUID curl https://api.shilo.ai/api/v1/users/ee6f2136-b94a-4438-9335-3acf5b2a0d31 \ -H "x-api-key: YOUR_API_KEY" # By Shilo UUID with explicit prefix curl "https://api.shilo.ai/api/v1/users/id:ee6f2136-b94a-4438-9335-3acf5b2a0d31" \ -H "x-api-key: YOUR_API_KEY" # By your system's user ID curl "https://api.shilo.ai/api/v1/users/external_user_id:agent-123" \ -H "x-api-key: YOUR_API_KEY" ``` ## Updating a User Send a `PUT` request with the fields you want to change: ```bash theme={null} curl -X PUT "https://api.shilo.ai/api/v1/users/external_user_id:agent-123" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Alexandra Johnson", "timezone": "America/Chicago" }' ``` ## Updating a User's Email Email updates have a dedicated endpoint to prevent accidental overwrites. Both `existing_email` and `updated_email` are required: `existing_email` identifies the current account and `updated_email` is the new address to assign: ```bash theme={null} curl -X PUT "https://api.shilo.ai/api/v1/users/external_user_id:agent-123/update_email" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "existing_email": "alex@example.com", "updated_email": "alex.new@example.com" }' ``` ## Suspending a User When an agent leaves your team, suspend their Shilo membership with a `DELETE` request: ```bash theme={null} curl -X DELETE "https://api.shilo.ai/api/v1/users/external_user_id:agent-123" \ -H "x-api-key: YOUR_API_KEY" ``` A successful suspension returns `204 No Content`. Suspending a user **does not delete** their Shilo account or remove their call history. It suspends their membership for your integration only. Their data remains accessible through the API. Additionally, Zillow Flex Advisor users are not affected by this endpoint—their membership is managed separately. ## User Signal Retrieve the latest Shilo Signal for an agent. A Signal is the latest AI-derived behavioral and communication profile for the user, useful for coaching, preparation, and adapting your approach in one-on-ones: ```bash theme={null} curl "https://api.shilo.ai/api/v1/users/external_user_id:agent-123/signal" \ -H "x-api-key: YOUR_API_KEY" ``` ## Invitations Use the Invitations API to onboard new agents who haven't yet accepted a Shilo invite. This is especially useful when provisioning users programmatically during your integration setup. ### Create an Invitation `email` and `external_user_id` are required. Exactly one of `invited_by_user_id` or `invited_by_email` is also required. `name` and `first_name` are optional. `role` is optional and may only be `ADMIN` or `MEMBER`, defaulting to `MEMBER`: ```bash theme={null} curl -X POST https://api.shilo.ai/api/v1/invitations \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "newagent@example.com", "external_user_id": "agent-789", "name": "Jordan Smith", "first_name": "Jordan", "role": "MEMBER", "invited_by_email": "manager@example.com" }' ``` **Possible responses:** | Status | Meaning | | -------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `201 Created` | Invitation successfully created and the invitation workflow queued. Status is `PENDING` | | `200 OK` | A pending invitation for this email already exists; the existing invitation is returned | | `409 Conflict` | A pending invitation exists for this email but with a **different** `external_user_id`; resolve the conflict before retrying | ### List Pending Invitations ```bash theme={null} curl "https://api.shilo.ai/api/v1/invitations?sort=desc" \ -H "x-api-key: YOUR_API_KEY" ``` ### Resend an Invitation ```bash theme={null} curl -X POST "https://api.shilo.ai/api/v1/invitations/INVITATION_ID/resend" \ -H "x-api-key: YOUR_API_KEY" ``` A successful resend returns `202 Accepted`. ### Cancel an Invitation ```bash theme={null} curl -X DELETE "https://api.shilo.ai/api/v1/invitations/INVITATION_ID" \ -H "x-api-key: YOUR_API_KEY" ``` A successful cancellation returns `204 No Content`. ## Keeping Users in Sync Because Shilo supports `external_user_id` as an identifier, you can build a robust sync without storing Shilo UUIDs in your system: 1. When a new agent joins your team, `POST /api/v1/invitations` with their `external_user_id`. 2. Once they accept and appear in `GET /api/v1/users`, reference them with `external_user_id:{your-id}` in all subsequent calls. 3. When an agent leaves, `DELETE /api/v1/users/external_user_id:{your-id}` to suspend their membership. Write operations (POST, PUT, DELETE) on users and invitations require a read-write API key. A read-only key returns `403 Forbidden` on these endpoints. # Retrieve and Interpret AI Call Analysis from Shilo Source: https://docs.shilo.ai/guides/retrieving-analysis Learn how to poll for completed AI analysis on calls, appointments, and roleplays, and how to read each analysis field returned by Shilo. Once you submit a recording to Shilo, the AI pipeline processes it asynchronously. Retrieving analysis requires polling the appropriate endpoint until the `progress` field reaches `100`, then reading the structured result. This guide covers the polling pattern, every analysis field, and how to retrieve the full call transcript. ## Analysis Endpoints All three recording types expose identical analysis and transcript endpoints: | Resource | Analysis endpoint | Transcript endpoint | | ------------ | ------------------------------------------------ | -------------------------------------------------- | | Calls | `GET /api/v1/calls/{identifier}/analysis` | `GET /api/v1/calls/{identifier}/transcript` | | Appointments | `GET /api/v1/appointments/{identifier}/analysis` | `GET /api/v1/appointments/{identifier}/transcript` | | Roleplays | `GET /api/v1/roleplays/{identifier}/analysis` | `GET /api/v1/roleplays/{identifier}/transcript` | ## Choosing Your Identifier Right after submitting a call, use the `call_event_id` from the `202` response as your identifier: ```text theme={null} call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31 ``` Once analysis completes and you have retrieved the full call object (which contains the stable Shilo `id`), you can switch to the plain UUID for any subsequent lookups. You can also use `external_recording_id:{your-recording-id}` at any time if you prefer to reference calls by your own IDs. ## Polling Until Complete The `progress` field in the analysis response is an integer from `0` to `100`. Keep polling until it equals `100`. ```bash theme={null} curl https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis \ -H "x-api-key: YOUR_API_KEY" ``` **While processing** (`progress < 100`): ```json theme={null} { "id": "a1b2c3d4-0000-0000-0000-111122223333", "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "created_at": "2030-09-24T12:34:56Z", "progress": 60 } ``` **When complete** (`progress == 100`), processing has finished. Individual sub-objects (`action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, and `summary`) are optional and may still be `null` or omitted, so check for presence on each field before reading it. Use exponential backoff when polling. Start with a 5-second interval, then double it on each unsuccessful poll up to a maximum of 60 seconds. Most calls complete within a few seconds to a few minutes depending on recording length. ## Analysis Fields ### `rating` The AI's numeric assessment of the call quality. ```json theme={null} "rating": { "id": "r1r1r1r1-0000-0000-0000-000000000001", "outcome": 4, "reasoning": "Strong rapport and clear value proposition; discovery questions could be more open-ended." } ``` * **`outcome`** (number) — Numeric score representing overall call quality or outcome result * **`reasoning`** (string) — Human-readable explanation of the score ### `summary` A concise narrative of the call. The `outcome` field may be either an object (commonly `{ "summary": string }`) or a plain string, so clients must handle both shapes. Object form: ```json theme={null} "summary": { "id": "s1s1s1s1-0000-0000-0000-000000000002", "outcome": { "summary": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday." } } ``` String form: ```json theme={null} "summary": { "id": "s1s1s1s1-0000-0000-0000-000000000002", "outcome": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday." } ``` * **`outcome`** (object | string) — Either an object with a `summary` field or a plain summary string. * **`outcome.summary`** (string) — When `outcome` is an object, the natural-language summary of the conversation. ### `coaching` Structured coaching feedback for the agent. ```json theme={null} "coaching": { "id": "c1c1c1c1-0000-0000-0000-000000000003", "possible_improvements": [ "Ask more open-ended discovery questions before presenting price", "Acknowledge objections before pivoting to benefits" ], "top_moments": [ "Handled the timeline objection with a compelling urgency frame", "Confirmed next steps clearly at the end of the call" ] } ``` * **`possible_improvements`** (string\[]) — Specific behaviors to work on in future calls * **`top_moments`** (string\[]) — Positive highlights worth reinforcing in coaching sessions ### `disposition` The AI's classification of the call outcome. ```json theme={null} "disposition": { "id": "d1d1d1d1-0000-0000-0000-000000000004", "outcomes": ["Qualified lead"], "reasoning": "Prospect confirmed budget and expressed positive intent to move forward." } ``` * **`outcomes`** (string\[]) — One or more outcome labels for the call * **`reasoning`** (string) — Explanation for the classification ### `objections` Objections the prospect raised during the conversation. ```json theme={null} "objections": { "id": "o1o1o1o1-0000-0000-0000-000000000005", "outcomes": ["Price concerns", "Needs to consult spouse"] } ``` * **`outcomes`** (string\[]) — List of objection strings identified by the AI ### `action_items` Follow-up tasks extracted from the call, split by priority. ```json theme={null} "action_items": { "id": "ai1ai1a1-0000-0000-0000-000000000006", "primary": ["Schedule follow-up appointment for next Thursday"], "secondary": ["Send recap email with listing details"] } ``` * **`primary`** (string\[]) — High-priority tasks the agent should act on immediately * **`secondary`** (string\[]) — Supporting or lower-priority follow-up actions ### `speakers` AI-resolved speaker identities. ```json theme={null} "speakers": { "id": "sp1sp1s1-0000-0000-0000-000000000007", "user_name": "Alex Johnson", "client_name": "Jamie Rivera" } ``` * **`user_name`** (string) — Resolved name of the agent, reconciled against your user data * **`client_name`** (string) — Resolved name of the client or prospect ## Complete Example Response The following payload shows what a fully populated response can look like. It is an illustrative example, not a guaranteed shape: any of `action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, and `summary` may be `null` or omitted, and `summary.outcome` may be an object or a string. ```json theme={null} { "id": "a1b2c3d4-0000-0000-0000-111122223333", "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "created_at": "2030-09-24T12:34:56Z", "progress": 100, "rating": { "id": "r1r1r1r1-0000-0000-0000-000000000001", "outcome": 4, "reasoning": "Strong rapport and clear value proposition; discovery questions could be more open-ended." }, "summary": { "id": "s1s1s1s1-0000-0000-0000-000000000002", "outcome": { "summary": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday." } }, "coaching": { "id": "c1c1c1c1-0000-0000-0000-000000000003", "possible_improvements": [ "Ask more open-ended discovery questions before presenting price", "Acknowledge objections before pivoting to benefits" ], "top_moments": [ "Handled the timeline objection with a compelling urgency frame", "Confirmed next steps clearly at the end of the call" ] }, "disposition": { "id": "d1d1d1d1-0000-0000-0000-000000000004", "outcomes": ["Qualified lead"], "reasoning": "Prospect confirmed budget and expressed positive intent to move forward." }, "objections": { "id": "o1o1o1o1-0000-0000-0000-000000000005", "outcomes": ["Price concerns", "Needs to consult spouse"] }, "action_items": { "id": "ai1ai1a1-0000-0000-0000-000000000006", "primary": ["Schedule follow-up appointment for next Thursday"], "secondary": ["Send recap email with listing details"] }, "speakers": { "id": "sp1sp1s1-0000-0000-0000-000000000007", "user_name": "Alex Johnson", "client_name": "Jamie Rivera" } } ``` ## Retrieving the Transcript Once speaker resolution is complete, you can retrieve the full sanitized transcript with AI-resolved speaker labels: ```bash theme={null} curl https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/transcript \ -H "x-api-key: YOUR_API_KEY" ``` If the transcript is not yet ready, you receive a `409 Conflict` response. Wait a moment and retry. For Shilo accounts connected to Follow Up Boss, only the **call and appointment** transcript endpoints (`GET /api/v1/calls/{identifier}/transcript` and `GET /api/v1/appointments/{identifier}/transcript`) are unsupported and return `403 Forbidden` with a message indicating the CRM integration limitation. The roleplay transcript endpoint, `GET /api/v1/roleplays/{identifier}/transcript`, remains supported for all integrations, including Follow Up Boss. # Submit Call Recordings for AI Analysis with Shilo Source: https://docs.shilo.ai/guides/submitting-calls Learn how to POST call recordings to Shilo's API for AI processing, including required fields, optional metadata, and handling the async response. Shilo's call submission endpoint accepts a recording URL and associated metadata, queues the call for AI processing, and returns a `call_event_id` you can use to poll for results. The entire pipeline is asynchronous—your system receives an immediate `202 Accepted` response, and Shilo handles the transcription, speaker resolution, and AI analysis in the background. ## Overview **Endpoint:** `POST /api/v1/calls`\ **Authentication:** Read-write API key required\ **Response:** `202 Accepted` with `call_event_id` and `status: "QUEUED"` ### Prepare Your Recording URL Before submitting, make sure the audio file at `recording_url` is publicly accessible. Shilo's processing pipeline will attempt to download the file at analysis time. If the URL is behind authentication or expires before processing starts, the job will fail. Use a pre-signed URL with a sufficiently long expiry (at least 30 minutes) if your storage provider requires signed URLs for access. ### Build the Request Body Construct a JSON body with all required fields. Optional fields can be included to enrich the contact and user records associated with the call. **Required fields:** | Field | Type | Description | | --------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- | | `recording_id` | string | Your unique external ID for this recording. Used for deduplication and as an identifier with the `external_recording_id:` prefix. | | `recording_url` | string | Publicly accessible URL to the audio file | | `duration_seconds` | number | Length of the recording in seconds | | `ai_category` | string | Analysis category (e.g. `"sales"`) | | `external_user_id` | string | Your system's ID for the agent on the call | | `user_name` | string | Agent display name | | `user_email` | string | Agent email address | | `external_contact_id` | string | Your system's ID for the contact or lead | | `contact_name` | string | Contact display name | **Optional fields:** | Field | Type | Description | | -------------------- | ----------------- | ------------------------------------------------------- | | `occurred_at` | string (ISO 8601) | When the call took place | | `from_number` | string | Caller phone number | | `to_number` | string | Recipient phone number | | `incoming` | boolean | `true` if the call was inbound | | `ai_models` | array | Override the AI models used for specific analysis types | | `user_timezone` | string | Agent's timezone (e.g. `"America/Denver"`) | | `user_picture` | string | URL to agent profile photo | | `contact_first_name` | string | Contact's first name | | `contact_last_name` | string | Contact's last name | | `contact_phone` | string | Contact's phone number | | `contact_emails` | string\[] | Contact's email addresses | | `contact_stage` | string | CRM stage name (e.g. `"Discovery"`) | | `contact_stage_id` | string | CRM stage ID | | `contact_source` | string | Lead source name (e.g. `"Broker"`) | | `contact_source_id` | string | Lead source ID | | `contact_tags` | string\[] | Tags to associate with the contact | ### Submit the Call Send the `POST` request with your API key and the JSON body: ```bash theme={null} curl -X POST https://api.shilo.ai/api/v1/calls \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "recording_id": "rec-001", "recording_url": "https://your-storage.example.com/recordings/rec-001.mp3", "duration_seconds": 187, "ai_category": "sales", "external_user_id": "agent-123", "user_name": "Alex Johnson", "user_email": "alex@example.com", "external_contact_id": "contact-456", "contact_name": "Jamie Rivera", "occurred_at": "2030-09-24T12:00:00Z", "from_number": "(555) 555-1234", "to_number": "(555) 555-5678", "incoming": false, "user_timezone": "America/Denver", "contact_first_name": "Jamie", "contact_last_name": "Rivera", "contact_stage": "Discovery", "contact_source": "Broker" }' ``` ### Save the `call_event_id` A successful submission returns `202 Accepted`: ```json theme={null} { "call_event_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "status": "QUEUED" } ``` Store the `call_event_id` in your system. You will use it immediately to poll for analysis using the `call_event_id:{uuid}` identifier pattern. ### Poll for Analysis Retrieve analysis once processing completes: ```bash theme={null} curl https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis \ -H "x-api-key: YOUR_API_KEY" ``` Poll until the `progress` field in the response equals `100`. See the [Retrieve Analysis guide](/guides/retrieving-analysis) for the full polling pattern and a description of every analysis field. ## Error Responses | Status | Meaning | Resolution | | ------------------ | ---------------------------------------------------------------------- | --------------------------------------------------------- | | `400 Bad Request` | The request body is missing required fields or contains invalid values | Check the error message for which field failed validation | | `403 Forbidden` | Your API key is read-only | Use a read-write API key for this endpoint | | `401 Unauthorized` | The API key is missing or invalid | Verify the `x-api-key` header and key value | ## AI Model Overrides If your Shilo plan supports custom AI models, you can override the model used for specific analysis types by including the `ai_models` array: ```json theme={null} { "ai_models": [ { "type": "coaching", "model": "custom_coaching_model_v2" } ] } ``` Contact your Shilo account manager for available model identifiers. # Shilo: AI Sales Coaching for High-Performing Real Estate Teams Source: https://docs.shilo.ai/introduction Shilo analyzes call recordings with AI to surface coaching, ratings, transcripts, and metrics. Learn what the API can do and how it's organized. Shilo is an AI-powered sales coaching platform that ingests call recordings, appointment recordings, and roleplay sessions, then returns actionable analysis to help your team improve on every conversation. The Shilo API gives you programmatic access to that same intelligence—so you can embed coaching data directly into your existing CRM, dashboards, or internal tools without leaving your workflow. ## What Shilo Does When you submit a recording to Shilo, the AI pipeline transcribes the audio, identifies speakers, scores the call, and surfaces structured coaching insights. These results power the Shilo web app and are equally available through the REST API. AI analysis returns the following for each recording: | Field | Description | | ----------------- | ------------------------------------------------------------------------------------ | | **rating** | A numeric outcome score plus a human-readable reasoning string explaining the score | | **summary** | A concise natural-language summary of what happened on the call | | **coaching** | Possible improvements the agent can act on, plus standout top moments | | **disposition** | The call outcome classification (e.g. qualified lead, not interested) with reasoning | | **objections** | Specific objections the prospect raised during the conversation | | **action\_items** | Primary and secondary follow-up tasks identified from the call | | **speakers** | AI-resolved agent and client names, reconciled against your user and contact data | | **transcript** | Full sanitized transcript with AI-resolved speaker labels | ## Key Resources The API is organized around these resource types: * **Calls** — Standard sales call recordings submitted via the API or a connected integration * **Appointments** — Appointment or meeting recordings, typically longer-form conversations * **Roleplays** — Practice scenarios where agents rehearse pitches or objection handling * **Contacts** — The leads and clients your agents speak with * **Users** — The agents and team members in your Shilo organization * **Invitations** — Pending invites for new agents who haven't yet joined Shilo * **Metrics** — Dashboard-aligned rollup statistics scoped to your integration, a user, or a contact * **Coaching** — 1:1 coaching periods, per-agent agendas, and team digest documents ## How the API Works The Shilo API is a REST API. Every request and response uses JSON. All endpoints are served from: ```text theme={null} https://api.shilo.ai/api/v1 ``` Authentication is handled via an API key sent in a request header. Calls are accepted asynchronously—when you submit a recording you receive a `202 Accepted` response immediately, and you poll the analysis endpoint until processing completes. Most list endpoints use cursor-based pagination and accept `limit`, `cursor`, and `sort` query parameters. ## Get Started Generate an API key and learn both supported header formats. Submit your first call and retrieve AI analysis in five steps. Explore every endpoint, request schema, and response model. # MCP Source: https://docs.shilo.ai/mcp-server Connect AI assistants and agent frameworks to Shilo's hosted MCP server and explore the available read-only tools. Shilo's hosted Model Context Protocol (MCP) server gives compatible AI assistants and agent frameworks secure, structured access to your Shilo data. Connect once, then use natural language to find contacts and users, inspect calls, prepare for appointments, and retrieve performance metrics. > The Shilo MCP server is read-only. It does not create, update, or delete data in Shilo or your CRM. ## Quickstart ### 1. Generate a Shilo API key The MCP server uses the same API keys as the Shilo REST API. An owner or admin can create one in **Settings → API Keys → Generate API Key**. Keep **Read-only Key** turned on, give the key a descriptive name such as `MCP - Claude` or `MCP - Cursor`, and copy it immediately. Shilo will not display the secret again. See [Authentication](/authentication) for full key-management and security guidance. ### 2. Add Shilo to your MCP client Use the following connection details: | Setting | Value | | ------------------------ | ------------------------------------------ | | Name | `Shilo` | | Transport | Streamable HTTP | | URL | `https://mcp.shilo.ai` | | Authentication | `x-api-key: YOUR_SHILO_API_KEY` | | Alternate authentication | `Authorization: Bearer YOUR_SHILO_API_KEY` | Your client must support remote Streamable HTTP servers and custom request headers. Many MCP clients accept configuration similar to this: ```json theme={null} { "mcpServers": { "shilo": { "url": "https://mcp.shilo.ai", "headers": { "x-api-key": "YOUR_SHILO_API_KEY" } } } } ``` Configuration fields vary by client. If your client supports environment-variable or secret references, use one instead of storing the key directly in the configuration file. ### 3. Confirm the connection Save the configuration, restart or reconnect your MCP client if required, and ask it to list the available Shilo tools. You can separately verify that the hosted server is available: ```bash theme={null} curl https://mcp.shilo.ai/health ``` A healthy server returns `OK`. This health check confirms availability only; it does not validate your API key. ## Available tools All tools are read-only and return structured data that an MCP client can reason over or pass to another workflow. | Tool | What it does | Key inputs | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | | `prepare_appointment_context` | Builds a compact appointment-prep packet with the user, contact, recent calls and analysis, and available Shilo Signals. | `external_user_id`, `external_contact_id`, optional `recent_calls_limit` | | `search_contacts` | Finds contacts by name, email, phone, or external contact ID. | Search fields plus optional `limit`, `cursor`, and `sort` | | `get_contact_context` | Retrieves a contact with optional Shilo Signal and recent-call context. | `external_contact_id`, optional `include_signal`, `include_recent_calls`, and `recent_calls_limit` | | `search_users` | Finds Shilo users—agents and team members—by name, email, or external user ID. | Search fields plus optional `limit`, `cursor`, and `sort` | | `get_user_context` | Retrieves a user with optional Shilo Signal and performance metrics. | `external_user_id`, optional `include_signal` and `include_metrics` | | `list_calls` | Lists recent calls using cursor-based pagination. | Optional `limit`, `cursor`, and `sort` | | `get_call_context` | Retrieves one call with optional analysis and transcript context. | `call_id`, optional `include_analysis` and `include_transcript` | | `list_appointments` | Lists appointment recordings using cursor-based pagination. | Optional `limit`, `cursor`, and `sort` | | `get_performance_metrics` | Retrieves dashboard-aligned metrics for the API key's integration, a user, or a contact. | `target_type` and, when needed, `external_user_id` or `external_contact_id` | ## Identifiers and pagination Context tools use the external IDs from your connected CRM. Use `search_contacts` or `search_users` first when you do not already know an ID. `get_call_context` uses the Shilo call ID returned by `list_calls`. Search and list tools return 25 records by default and accept a maximum `limit` of 100. When `pagination.has_more` is `true`, pass `pagination.next_cursor` into the next request. Appointment prep and contact context tools return up to three recent calls by default and accept a maximum of five. Optional data may not exist for every record. Context tools return a `warnings` array when a requested signal, analysis, transcript, or related object cannot be included. ## Example prompts Once connected, try prompts like: * "Find Jamie Client, then prepare me for my next appointment with them using recent calls and Shilo Signals." * "Show me the context for the most recent call, including the analysis and transcript." * "Find the user with the email [alex@example.com](mailto:alex@example.com) and summarize their current performance metrics." * "List the most recent appointments and identify which contacts need follow-up." * "Find a contact by phone number and summarize what happened in their recent conversations." Your MCP client decides when and how to call tools. For more reliable results, name the contact or user clearly and specify whether you want signals, metrics, recent calls, analysis, or transcript data. ## Security Treat your Shilo API key like a password. * Use a dedicated read-only key for each MCP client or integration. * Never commit a key to source control or paste it into a public prompt. * Prefer environment variables or a secrets manager when your client supports them. * Revoke unused or exposed keys from **Settings → API Keys**. * Remember that each key is scoped to its associated Shilo integration. ## Troubleshooting ### The client returns `401 Unauthorized` The key is missing, invalid, mistyped, or revoked. Confirm that the configured header is either `x-api-key` or `Authorization: Bearer` and that it contains the complete key. ### The client cannot connect or discover tools Confirm that the URL is exactly `https://mcp.shilo.ai` and that the client supports Streamable HTTP plus custom headers. Save the configuration and restart the client if it does not automatically reconnect. ### A contact, user, or call is not found Check that you are using the expected identifier and that the API key belongs to the Shilo integration that contains the record. Search for the contact or user first when you are unsure of the external ID. ### Optional context is missing Signals, analyses, transcripts, and metrics are not available for every record. Review the tool's `warnings` array for the specific reason. # Get Started with the Shilo API in Minutes Source: https://docs.shilo.ai/quickstart Submit your first call recording to Shilo and retrieve AI-generated analysis in five steps. Covers authentication, call creation, and polling for results. This guide walks you through the complete lifecycle of a Shilo API call: generating a key, submitting a recording, and reading back the AI analysis. By the end you will have a working integration pattern you can adapt to any language or framework. The five steps below cover everything from authentication to inspecting the available analysis fields. ## Step 1: Generate an API key In the Shilo dashboard, navigate to **Settings > API Keys > Generate API Key** and create a **read-write** key. Copy the key immediately, it is only shown once. Store it as a secret in your environment (for example, `SHILO_API_KEY`) and never commit it to source control. ## Step 2: Prepare a recording URL Host your call recording at a publicly accessible URL that Shilo can fetch over HTTPS. Common patterns include a signed S3 URL, a Cloudflare R2 public link, or any CDN-hosted audio file. Make sure the URL resolves without additional authentication for the duration of processing. ## Step 3: Submit the call Send a `POST` to `https://api.shilo.ai/api/v1/calls` with your API key in the `x-api-key` header and a JSON body containing every required field. ```bash cURL theme={null} curl -X POST https://api.shilo.ai/api/v1/calls \ -H "x-api-key: $SHILO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "recording_id": "rec_2f7a91", "recording_url": "https://cdn.example.com/calls/rec_2f7a91.mp3", "duration_seconds": 842, "ai_category": "sales", "external_user_id": "usr_alex_01", "user_name": "Alex Rivera", "user_email": "alex@example.com", "external_contact_id": "cnt_jordan_42", "contact_name": "Jordan Lee" }' ``` A successful submission returns `202 Accepted` with the queued call event. ```json 202 Accepted theme={null} { "call_event_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31", "status": "QUEUED" } ``` ## Step 4: Poll for analysis Save the `call_event_id` and poll `GET /api/v1/calls/call_event_id:{call_event_id}/analysis` using the same API key. Continue polling until `progress` reaches `100`. ```bash cURL theme={null} curl https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis \ -H "x-api-key: $SHILO_API_KEY" ``` `progress: 100` means processing is complete. Individual analysis objects can still be absent or `null` depending on the call's content and length, so treat each sub-object as optional in your integration. ## Step 5: Inspect the analysis Once processing is complete, read the fields your workflow needs. The analysis response can include: * `rating`, a numeric quality score for the call. * `summary`, an AI-generated recap. * `coaching`, structured coaching feedback for the rep. * `disposition`, the call outcome classification. * `objections`, buyer objections detected in the conversation. * `action_items`, follow-ups surfaced from the discussion. * `speakers`, AI-resolved user and client names. Any of these may be missing or `null` on a given call, so check for presence before accessing nested fields. For deeper coverage of every request and response field, see the [Submit Calls](/guides/submitting-calls) and [Retrieve Analysis](/guides/retrieving-analysis) guides. ## Next Steps Learn all required and optional fields for the call creation endpoint. Deep-dive into every analysis field and the polling pattern. Understand the prefix:value identifier system used across all resources. Page through large result sets with cursor-based pagination.