Skip to main content
The Sully.ai API extracts standardized medical codes from clinical text, enabling automated billing workflows and clinical documentation. This guide covers submitting coding requests, understanding results, and integrating with your clinical workflow.

Overview

Sully.ai analyzes clinical text (transcripts or notes) and extracts relevant medical codes with their source locations. The API supports three major coding systems:
Code SystemPurposeExample
ICD-10-CMDiagnosis codes for billing and classificationG43.909 (Migraine, unspecified)
CPTProcedure codes for services rendered99213 (Office visit, established patient)
SNOMED CTClinical terminology for interoperability37796009 (Migraine)

Supported Code Systems

ICD-10-CM (Diagnoses)

The International Classification of Diseases, 10th Revision, Clinical Modification is the standard for diagnosis coding in the United States. Sully.ai extracts ICD-10-CM codes for conditions, symptoms, and diagnoses mentioned in clinical text.

CPT (Procedures)

Current Procedural Terminology codes describe medical procedures and services. Sully.ai identifies procedure codes based on the clinical context and services documented.

SNOMED CT (Clinical Terminology)

Systematized Nomenclature of Medicine - Clinical Terms provides comprehensive clinical vocabulary. SNOMED CT codes are included alongside ICD-10-CM codes for diagnoses to support clinical interoperability.

Code Extraction by Type

Clinical ElementCode Systems Extracted
DiagnosesICD-10-CM, SNOMED CT
ProceduresCPT

Creating a Coding Request

Submit clinical text to extract medical codes. The coding operation is asynchronous and returns a coding ID for result retrieval.
import SullyAI from '@sullyai/sullyai';

const client = new SullyAI();

// Submit clinical text for coding
const coding = await client.codings.create({
  text: "Patient presents with migraine headache, experiencing throbbing pain on the right side for 3 days. Photophobia and nausea present. Started on sumatriptan 50mg as needed. Follow-up visit scheduled in 2 weeks.",
});

console.log('Coding ID:', coding.codingId);

Input Options

FieldTypeDescription
textstringClinical text to analyze (transcript or note content)
You can submit either raw transcripts or generated clinical notes. Notes often produce more accurate coding results because they contain structured clinical information.

Polling for Results

After submitting a coding request, poll the endpoint until processing completes.

Status Flow

StatusDescription
pendingRequest received, queued for processing
processingActively analyzing clinical text
completedCodes extracted, available in result
failedAn error occurred during processing

Polling Example

import SullyAI from '@sullyai/sullyai';

const client = new SullyAI();

// Poll until coding completes
let result = await client.codings.retrieve(coding.codingId);

while (result.status === 'pending' || result.status === 'processing') {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  result = await client.codings.retrieve(coding.codingId);
}

if (result.status === 'failed') {
  throw new Error('Coding extraction failed');
}

console.log('Diagnoses:', result.result.diagnoses);
console.log('Procedures:', result.result.procedures);

Understanding Results

When coding completes, the result object contains arrays of diagnoses and procedures, each with associated codes and source text locations.

Diagnoses

The result.diagnoses array contains diagnosed conditions with their codes:
{
  "diagnoses": [
    {
      "id": "diag_001",
      "code": {
        "coding": [
          {
            "system": "http://hl7.org/fhir/sid/icd-10-cm",
            "code": "G43.909",
            "display": "Migraine, unspecified, not intractable"
          },
          {
            "system": "http://snomed.info/sct",
            "code": "37796009",
            "display": "Migraine"
          }
        ],
        "text": "Migraine headache"
      },
      "text_span": {
        "start_char": 22,
        "end_char": 38,
        "text": "migraine headache"
      }
    }
  ]
}
FieldDescription
idUnique identifier for the diagnosis
code.codingArray of codes from different systems (ICD-10-CM, SNOMED CT)
code.textHuman-readable description
text_spanSource location in the input text

Procedures

The result.procedures array contains identified procedures with CPT codes:
{
  "procedures": [
    {
      "id": "proc_001",
      "code": {
        "coding": [
          {
            "system": "http://www.ama-assn.org/go/cpt",
            "code": "99213",
            "display": "Office visit, established patient, low complexity"
          }
        ],
        "text": "Office visit"
      },
      "text_span": {
        "start_char": 156,
        "end_char": 177,
        "text": "Follow-up visit"
      }
    }
  ]
}
FieldDescription
idUnique identifier for the procedure
code.codingArray of CPT codes
code.textHuman-readable description
text_spanSource location in the input text

Code Systems Reference

System URICode System
http://hl7.org/fhir/sid/icd-10-cmICD-10-CM
http://snomed.info/sctSNOMED CT
http://www.ama-assn.org/go/cptCPT

Full Response Example

{
  "data": {
    "codingId": "cod_abc123def456",
    "status": "completed",
    "created_at": "2024-01-24T15:30:00Z",
    "updated_at": "2024-01-24T15:30:05Z",
    "result": {
      "diagnoses": [
        {
          "id": "diag_001",
          "code": {
            "coding": [
              {
                "system": "http://hl7.org/fhir/sid/icd-10-cm",
                "code": "G43.909",
                "display": "Migraine, unspecified, not intractable"
              },
              {
                "system": "http://snomed.info/sct",
                "code": "37796009",
                "display": "Migraine"
              }
            ],
            "text": "Migraine headache"
          },
          "text_span": {
            "start_char": 22,
            "end_char": 38,
            "text": "migraine headache"
          }
        },
        {
          "id": "diag_002",
          "code": {
            "coding": [
              {
                "system": "http://hl7.org/fhir/sid/icd-10-cm",
                "code": "R11.0",
                "display": "Nausea"
              },
              {
                "system": "http://snomed.info/sct",
                "code": "422587007",
                "display": "Nausea"
              }
            ],
            "text": "Nausea"
          },
          "text_span": {
            "start_char": 95,
            "end_char": 101,
            "text": "nausea"
          }
        }
      ],
      "procedures": [
        {
          "id": "proc_001",
          "code": {
            "coding": [
              {
                "system": "http://www.ama-assn.org/go/cpt",
                "code": "99213",
                "display": "Office visit, established patient, low complexity"
              }
            ],
            "text": "Office visit"
          },
          "text_span": {
            "start_char": 156,
            "end_char": 177,
            "text": "Follow-up visit"
          }
        }
      ]
    }
  }
}

Coding + Notes Workflow

A common pattern is to transcribe audio, generate a clinical note, then extract codes. You can run coding on either the raw transcript or the generated note.
import SullyAI from '@sullyai/sullyai';
import * as fs from 'fs';

const client = new SullyAI();

async function transcribeNoteAndCode() {
  // 1. Transcribe audio
  const transcription = await client.audio.transcriptions.create({
    audio: fs.createReadStream('patient-visit.mp3'),
  });

  // Poll for transcription...
  let txResult = await client.audio.transcriptions.retrieve(
    transcription.transcriptionId
  );
  while (txResult.status === 'STATUS_PROCESSING') {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    txResult = await client.audio.transcriptions.retrieve(
      transcription.transcriptionId
    );
  }

  const transcript = txResult.payload?.transcription;

  // 2. Generate clinical note
  const note = await client.notes.create({
    transcript: transcript,
    noteType: { type: 'soap' },
  });

  // Poll for note...
  let noteResult = await client.notes.retrieve(note.noteId);
  while (noteResult.status === 'processing') {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    noteResult = await client.notes.retrieve(note.noteId);
  }

  const noteText = noteResult.payload?.markdown;

  // 3. Extract codes from the generated note
  const coding = await client.codings.create({
    text: noteText,
  });

  // Poll for coding...
  let codingResult = await client.codings.retrieve(coding.codingId);
  while (codingResult.status === 'pending' || codingResult.status === 'processing') {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    codingResult = await client.codings.retrieve(coding.codingId);
  }

  console.log('Diagnoses:', codingResult.result.diagnoses);
  console.log('Procedures:', codingResult.result.procedures);
}

Using Webhooks

For production applications, use webhooks instead of polling. Configure webhooks to receive coding.succeeded and coding.failed events.
import express from 'express';

const app = express();

app.post('/webhook', express.json(), (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'coding.succeeded':
      const { diagnoses, procedures } = event.data.result;
      console.log(`Coding ${event.data.id} completed`);
      console.log(`Found ${diagnoses.length} diagnoses, ${procedures.length} procedures`);
      // Store codes, update billing system, etc.
      break;

    case 'coding.failed':
      console.error(`Coding ${event.data.id} failed: ${event.data.error}`);
      // Handle failure, queue for manual review
      break;
  }

  res.status(200).send('OK');
});
For complete webhook setup including signature verification, see the Webhooks guide.

Validation and Review

Medical codes extracted by Sully.ai are suggestions to assist clinical and billing workflows. They are not definitive and should not be submitted for billing without human review.

Human Review Required

Always have qualified personnel review extracted codes before:
  • Submitting claims to payers
  • Recording codes in the patient’s medical record
  • Using codes for quality reporting

Using text_span for Verification

The text_span field helps reviewers verify the source context for each code:
function displayCodeWithContext(diagnosis: Diagnosis): void {
  const { code, text_span } = diagnosis;

  // Show the code
  const icd10 = code.coding.find(
    (c) => c.system === 'http://hl7.org/fhir/sid/icd-10-cm'
  );

  console.log(`Code: ${icd10?.code} - ${icd10?.display}`);
  console.log(`Source text: "${text_span.text}"`);
  console.log(`Location: characters ${text_span.start_char}-${text_span.end_char}`);
}

Best Practices

PracticeDescription
Review before billingAlways have certified coders verify extracted codes
Check specificityEnsure codes are at the appropriate level of specificity
Verify contextUse text_span to confirm codes match clinical documentation
Document reviewMaintain audit trail of code review and modifications
Monitor accuracyTrack coding accuracy over time to identify improvement areas

Common Validation Checks

  1. Code specificity - Ensure codes aren’t unspecified when more specific codes apply
  2. Code combinations - Verify that diagnosis and procedure codes align appropriately
  3. Medical necessity - Confirm procedures are supported by documented diagnoses
  4. Date alignment - Ensure coded services match the encounter date

Next Steps