Send a Georgia DFCS Service Authorization PDF, get structured JSON back — case details, every client on the authorization, and every authorized service line with units and dollar amounts.
/api/v1/extract.php.billing.balance_usd on each response, or call
/api/v1/balance.php.Prefer to click around first?
Download Postman collection View as JSON
Every endpoint, ready to run. In Postman: Import → drop the file in,
then open the collection's Variables tab and paste your key into api_key.
base_url is already set to https://sp330.getnums.com. On
Extract a document, choose a PDF for the file row on the Body tab —
Postman cannot save a file inside a collection, so that row arrives empty.
Send your key on every request:
Authorization: Bearer sp260_your_key_here
Or X-API-Key: sp260_... if a bearer header is inconvenient.
Issue and revoke your own keys on your account page.
POST https://sp330.getnums.com/api/v1/extract.php
curl -X POST https://sp330.getnums.com/api/v1/extract.php \ -H "Authorization: Bearer sp260_your_key_here" \ -F "[email protected]" \ --form-string "model=@cf/meta/llama-4-scout-17b-16e-instruct"
model is optional — drop that last line and
@cf/meta/llama-4-scout-17b-16e-instruct is used anyway, since it is the
default. Every model id is listed under Choosing a model.
--form-string. Model ids begin with
@, and curl reads -F "model=@..." as an instruction to upload a
local file of that name — it fails with "Failed to open/read local data" before
the request is even sent. --form-string sends the value literally. Use plain
-F for the file itself, where the @ is what you want.rendered_by when it happened.
images (an array of data URIs, one per page)
if you have already rendered them, which saves the server the work. On the rare host with no
PDF renderer installed, that becomes the only option and the API says so with
needs_page_images — you are not charged for that reply.POST /api/v1/extract.php
Content-Type: application/json
{
"filename": "service-authorization.pdf",
"text": "<the PDF text layer, or an empty string>",
"images": ["data:image/jpeg;base64,...", "..."],
"page_count": 8,
"model": "@cf/meta/llama-4-scout-17b-16e-instruct" // optional
}
Shown in full under Response format. In outline:
{
"success": true,
"message": "SA file analyzed successfully! Found case information.",
"data": { /* case, services, referred_persons - see below */ },
"file_path": "sa_files/SA_1785414778_authorization.pdf",
"billing": { "price_usd": 0.00259, "price_display": "$0.00259",
"balance_usd": 1.9974 }
}
{
"ok": true,
"api_version": 1,
"request_id": "req_1042",
"document": { "filename": "...", "sa_type": "type3",
"read_as": "vision", "page_count": 8, "pages_processed": 8,
"model": "@cf/meta/llama-4-scout-17b-16e-instruct",
"model_name": "Llama 4 Scout 17B" },
"case": {
"case_id": "18756136", "service_auth_id": "19324975",
"first_name": "Warrnette", "last_name": "Ward", "county": "Barrow",
"service_start": "02/06/2026", "service_end": "03/06/2026", ...
},
"case_manager": { "name": "Kim Mcdaniel", "supervisor": "Sarah Landers" },
// Every person the authorization covers. One SA often lists several
// siblings who share a single pool of units.
"clients": [
{ "first_name": "Nyla", "last_name": "Ward", "person_id": "21132979",
"service_start": "02/06/2026", "service_end": "03/06/2026" },
{ "first_name": "Zion", "last_name": "Ward", "person_id": "20709178", ... },
{ "first_name": "Kingston", "last_name": "Ward", "person_id": "21440002", ... }
],
"services": [
{ "uas": "518", "code": "47E", "description": "Behavioral Aide",
"units": 16, "rate": 38.5, "amount": 616, "end_date": "03/06/2026",
// true when these units cover ALL the clients above, not one of them
"shared_pool": true,
"needs_review": false, "review_note": null }
],
"totals": { "client_count": 3, "service_count": 3,
"total_authorized": 1146.64, "rows_needing_review": 0 },
"review": { "flags": {}, "warnings": [ ... ] },
"billing": { "price_usd": 0.0107, "price_display": "$0.0107",
"currency": "USD", "processing_ms": 21400 }
}
shared_pool: true marks
those rows. A pool of 32 across 5 children has no correct per-child value, so the API reports
the total rather than inventing a split.needs_review otherwise.review.warnings tells you what was corrected and why.This is what every call returns — there is no parameter to set.
success / message / data, ISO
YYYY-MM-DD dates, money as 2-decimal strings, and the service list flattened to
one row per client per service.
request_id,
api_version and billing.{
"success": true,
"message": "SA file analyzed successfully! Found case information.",
"data": {
"case_name": "Daisy Crowder", "case_id": "18916067",
"first_name": "Daisy", "last_name": "Crowder",
"service_authorization_id": "90225829",
"payment_county": "Pickens", "legal_county": "Pickens",
"date_referral_sent": "2026-01-27",
"effective_date": "2026-02-01", "case_start_date": "2026-02-01",
"expiry_date": "2026-03-01",
"provider_name": "Ally consultants",
// Flat: one row per client per service.
"services": [
{ "person_id": "18348646", "service_base_code": "518", "service_type_code": "47e",
"code": "518-47e", "uas": "518", "service_full_code": "518-47e",
"name": "Behavioral Aide", "type": "Behavioral Aide",
"units": 16, "rate": "38.50", "total_amount": "616.00",
"start_date": "2026-02-01", "end_date": "2026-03-01",
"should_ignore_units": false, "id": null, "person_name": null }
],
"referred_persons": [
{ "first_name": "Daisy", "last_name": "Crowder", "person_id": "18348646",
"address": "131 Lois Parks Dr.", "city": "Ellijay", "state": "Georgia", "zip": "30540",
"dob": "", "medicaid_id": "", "state_id": null,
"selected_services": [ /* that client's rows */ ] }
],
"assigned_case_manager": { "first_name": "Ulsi", "last_name": "Watson",
"full_name": "Ulsi Watson" },
"dfcs_cm_email": "[email protected]", "dfcs_cm_phone": "(706) 301-8997",
"dfcs_cm_id": null, "pay_county_id": null,
"pdf_type": "manual", "confidence_score": 95,
"extraction_date": "2026-07-30T11:40:22.032109Z",
"raw_text_preview": "Intake: [ ] ...",
"rates": [], "qualifications": [], "contact_info": [],
"validation_errors": []
},
"file_path": "sa_files/SA_1785411571_authorization.pdf",
"debug_info": { "extraction_method": "...", "processing_time": "...",
"file_uploaded": "yes", "extracted_fields": [ "..." ] }
}
When referred_persons has more than one entry, every client gets a full copy of
the services and units / total_amount come back
null with should_ignore_units: true. The authorization grants a
pool for the whole family and the form does not record how it splits — 32 units across
5 children has no correct per-child value, so you assign it, not us.
Clients after the first rarely have a Person ID printed. Theirs is
manual-2, manual-3 and so on: addressable, and obviously not a real
Person ID. A lone ID printed beside several names stays on the first client only.
A rejected call answers with success: false, a plain-English
message and data: null — including the ones that fail before
a model runs, like a bad key or an empty wallet. Branch on success; the HTTP
status agrees with it. error.code is also present for programmatic handling.
id on a service, state_id, dfcs_cm_id and
pay_county_id are primary keys in your database, not values on the PDF.
Filling them with a guess would attach a record to the wrong case manager or county, so they
are left null. Join on what the form actually prints:
service_full_code (e.g. 518-47e), payment_county,
and dfcs_cm_email.
Need the older native envelope? Send format=v1. It is kept for
anything already built against it and is not the default.
Two more honest limits. type repeats the short service name rather
than the long qualification paragraph — that text is not on the authorization.
service_authorization_id is null on manual forms, because they do
not carry one; only the generated forms print it.
Send model with the exact id from the table below. Leave it out and the
default is used, which is the right choice for almost everything — it reads scans and
handwriting and is the cheapest model that does.
# form-data curl -X POST https://sp330.getnums.com/api/v1/extract.php \ -H "Authorization: Bearer sp260_your_key" \ -F "[email protected]" \ --form-string "model=@cf/meta/llama-4-scout-17b-16e-instruct"
// or JSON
{ "filename": "authorization.pdf", "text": "...", "model": "@cf/meta/llama-4-scout-17b-16e-instruct" }
The response echoes what actually ran, so you can log it:
"document": { "read_as": "vision",
"model": "@cf/meta/llama-4-scout-17b-16e-instruct",
"model_name": "Llama 4 Scout 17B", ... }
| Model name | Pass this as model | Reads |
|---|---|---|
| Llama 3.2 11B Vision | @cf/meta/llama-3.2-11b-vision-instruct |
scans & handwriting |
| Gemma 4 26B | @cf/google/gemma-4-26b-a4b-it |
scans & handwriting |
| Llama 4 Scout 17B default | @cf/meta/llama-4-scout-17b-16e-instruct |
scans & handwriting |
| Mistral Small 3.1 24B | @cf/mistralai/mistral-small-3.1-24b-instruct |
scans & handwriting |
| Gemini 2.5 Flash | google/gemini-2.5-flash |
scans & handwriting |
| Kimi K2.7 | @cf/moonshotai/kimi-k2.7-code |
scans & handwriting |
| Kimi K2.6 | @cf/moonshotai/kimi-k2.6 |
scans & handwriting |
| Qwen 3 30B | @cf/qwen/qwen3-30b-a3b-fp8 |
text-layer PDFs only |
| GLM 4.7 Flash | @cf/zai-org/glm-4.7-flash |
text-layer PDFs only |
| GPT-OSS 20B | @cf/openai/gpt-oss-20b |
text-layer PDFs only |
| GPT-OSS 120B | @cf/openai/gpt-oss-120b |
text-layer PDFs only |
| Llama 3.3 70B | @cf/meta/llama-3.3-70b-instruct-fp8-fast |
text-layer PDFs only |
A text-only model cannot read a scanned or handwritten authorization. Send one
a document with no text layer and the call fails with needs_page_images rather
than returning a guess. GET https://sp330.getnums.com/api/v1/models.php returns this same
list as JSON, so you can validate a model id before sending. An unknown id returns
unknown_model; one that is not enabled returns model_locked.
Billed per request. billing.price_display on every response is what that call
cost — no subscription, no minimum commitment.
| Model | Per page | Typical 8-page scan | Reads |
|---|---|---|---|
Llama 3.2 11B Vision @cf/meta/llama-3.2-11b-vision-instruct |
$0.00040 | $0.00319 | scans & handwriting |
Gemma 4 26B @cf/google/gemma-4-26b-a4b-it |
$0.00049 | $0.00392 | scans & handwriting |
Llama 4 Scout 17Bdefault @cf/meta/llama-4-scout-17b-16e-instruct |
$0.00134 | $0.0107 | scans & handwriting |
Mistral Small 3.1 24B @cf/mistralai/mistral-small-3.1-24b-instruct |
$0.00157 | $0.0126 | scans & handwriting |
Gemini 2.5 Flash google/gemini-2.5-flash |
$0.00195 | $0.0156 | scans & handwriting |
Kimi K2.7 @cf/moonshotai/kimi-k2.7-code |
$0.00500 | $0.0400 | scans & handwriting |
Kimi K2.6 @cf/moonshotai/kimi-k2.6 |
$0.00500 | $0.0400 | scans & handwriting |
Qwen 3 30B @cf/qwen/qwen3-30b-a3b-fp8 |
$0.00031 | — | text-layer PDFs only |
GLM 4.7 Flash @cf/zai-org/glm-4.7-flash |
$0.00036 | — | text-layer PDFs only |
GPT-OSS 20B @cf/openai/gpt-oss-20b |
$0.00089 | — | text-layer PDFs only |
GPT-OSS 120B @cf/openai/gpt-oss-120b |
$0.00163 | — | text-layer PDFs only |
Llama 3.3 70B @cf/meta/llama-3.3-70b-instruct-fp8-fast |
$0.00185 | — | text-layer PDFs only |
The figures above are for a typical authorization page. What you are actually charged is measured from the work the document required, so a one-page referral costs a fraction of a long scan rather than a flat fee. Failed calls that never reach a model are not billed.
GET https://sp330.getnums.com/api/v1/balance.php — balance, spend and recent activity.
curl https://sp330.getnums.com/api/v1/balance.php -H "Authorization: Bearer sp260_your_key"
{
"ok": true, "api_version": 1, "currency": "USD",
"balance": { "amount_usd": 4.9793, "display": "$4.9793", "low": false },
"usage": { "window_days": 30, "requests": 2, "pages": 15,
"spend_usd": 0.0207, "spend_display": "$0.0207" },
"recent": [
{ "at": "2026-07-30 11:04:22", "type": "charge", "amount": -0.0107,
"display": "-$0.0107", "balance_after": 4.9793, "note": "extract sa-19324975.pdf" },
{ "at": "2026-07-30 10:58:01", "type": "topup", "amount": 5.0,
"display": "+$5.0000", "balance_after": 5.0, "note": "Admin top-up" }
]
}
Every extraction response already carries your balance after the charge, so you rarely need a separate call. Poll this before a large batch.
GET https://sp330.getnums.com/api/v1/usage.php?days=30 —
per-request history and a daily breakdown.
GET https://sp330.getnums.com/api/v1/models.php — models you may pass as
model, with prices.
The API is prepaid. Each call is charged to your balance and the response tells you what is left.
"price_usd": 0: bad key, rate limit, non-PDF, or a scan sent without page images.insufficient_credit (HTTP 402) and nothing is billed.topup.A scanned authorization covering three siblings — the hardest case the API handles.
curl -X POST https://sp330.getnums.com/api/v1/extract.php \ -H "Authorization: Bearer sp260_your_key" \ -F "[email protected]" \ -F "images[]=data:image/jpeg;base64,..." \ -F "page_count=8" \ --form-string "model=@cf/meta/llama-4-scout-17b-16e-instruct"
{
"ok": true, "api_version": 1, "request_id": "req_1042",
"document": { "filename": "SA-Ally-Jan2026.pdf", "sa_type": "type3",
"read_as": "vision", "page_count": 8, "pages_processed": 8,
"model": "@cf/meta/llama-4-scout-17b-16e-instruct",
"model_name": "Llama 4 Scout 17B" },
"case": { "case_id": "18756136", "service_auth_id": "",
"first_name": "Warrnette", "last_name": "Ward", "county": "Barrow",
"service_start": "02/06/2026", "service_end": "03/06/2026",
"provider_name": "Ally Consultants", "date_referral": "02/01/2026",
"street": "4115 Bridlegate Way", "city": "Snellville",
"state": "Georgia", "zip": "30039", "phone": "(678) 458-8367" },
"case_manager": { "name": "Kim Mcdaniel", "supervisor": "Sarah Landers" },
// One authorization, three children. Each carries the service window.
"clients": [
{ "first_name": "Nyla", "last_name": "Ward", "person_id": "21132979",
"service_start": "02/06/2026", "service_end": "03/06/2026" },
{ "first_name": "Zion", "last_name": "Ward", "person_id": "20709178",
"service_start": "02/06/2026", "service_end": "03/06/2026" },
{ "first_name": "Kingston", "last_name": "Ward", "person_id": "21440002",
"service_start": "02/06/2026", "service_end": "03/06/2026" }
],
"services": [
{ "uas": "518", "code": "47E", "description": "Behavioral Aide",
"units": 16, "rate": 38.5, "amount": 616, "end_date": "03/06/2026",
"shared_pool": true, "needs_review": false, "review_note": null },
{ "uas": "518", "code": "56A", "description": "WRAP Transporting/Escorting",
"units": 12, "rate": 29.48, "amount": 353.76, "end_date": "03/06/2026",
"shared_pool": true, "needs_review": false, "review_note": null },
{ "uas": "518", "code": "56AA", "description": "WRAP Transporting (Without Child)",
"units": 12, "rate": 14.74, "amount": 176.88, "end_date": "03/06/2026",
"shared_pool": true, "needs_review": false, "review_note": null }
],
"totals": { "client_count": 3, "service_count": 3,
"total_authorized": 1146.64, "rows_needing_review": 0 },
"review": { "flags": {}, "warnings": [
"This authorization covers 3 clients who share one pool of units..." ] },
"billing": { "price_usd": 0.0107, "price_display": "$0.0107", "currency": "USD",
"processing_ms": 21400,
"balance_usd": 4.9686, "balance_display": "$4.9686" }
}
shared_pool: true — those units cover all three children
together. They are the authorized total for the case, not one child's entitlement. How
they are divided is a decision the form does not record, so the API does not invent one.needs_review — the row did not reconcile on its own arithmetic
and was corrected or flagged. review_note says exactly what changed.review.warnings — everything the extractor corrected, in plain
language. Worth logging.totals.total_authorized — sums only rows that matched a real
entitlement code. Unmatched rows are reported but never added to the money.Failures use the same envelope; ok tells them apart.
{ "ok": false, "api_version": 1,
"error": { "code": "needs_page_images", "message": "..." },
"billing": { "price_usd": 0, "price_display": "$0.00", "currency": "USD" } }
| Code | HTTP | Meaning |
|---|---|---|
unauthorized | 401 | Missing, unknown or revoked key. |
rate_limited | 429 | Too many requests this minute. See Retry-After. |
not_a_pdf | 415 | The upload is not a PDF. |
file_too_large | 413 | Over the size limit. |
needs_page_images | 422 | Scanned PDF sent without page images. Not billed. |
unknown_model | 422 | model is not one from /models.php. |
insufficient_credit | 402 | Balance too low to start. Not billed. |
extraction_failed | 422 | Could not read the document. Billed — the model still ran. |