Skip to content

AI assistant API

These endpoints are what Settings → AI assistant and the AI assistant · advice only panel on an alert use. The assistant advises: asking it never changes the alert. Before you switch it on, read AI assistant security, which says what is sent to the model’s provider and how it is masked.

All of them need a signed-in session; add -b ~/.sp-cookies to every request below.

Endpoint What it does Permission Success
GET /api/v1/ai/settings The settings, this month’s usage and the agreement figures settings.view or settings.manage 200
PUT /api/v1/ai/settings Replace the settings settings.manage 200, or 202
POST /api/v1/ai/allowance-requests Ask the service provider for more calls this month settings.manage 200
GET /api/v1/alerts/{id}/ai-review The latest advice on an alert, and whether the assistant can be asked alerts.view 200, or 404
POST /api/v1/alerts/{id}/ai-review Ask the assistant about an open alert cases.work and entities.view 200
GET /api/v1/cases/{id}/ai-summary The latest summary of a case, and whether the assistant can be asked cases.view 200, or 404
POST /api/v1/cases/{id}/ai-summary Ask the assistant to summarise a case cases.work and entities.view 200
POST /api/v1/ai/batches Ask the assistant about many alerts or cases at once cases.work and entities.view 200
GET /api/v1/ai/batches/{id} How a batch is doing cases.work 200, or 404
GET /api/v1/ai/batches?kind= Your latest batch of a kind cases.work 200
GET /api/v1/ai/available Whether the assistant is switched on alerts.view or cases.view 200
GET /api/v1/reports/{id}/ai-narrative The latest draft of a report’s narrative, and whether one can be asked for reports.draft and entities.view_pii 200, or 404
POST /api/v1/reports/{id}/ai-narrative Ask the assistant to draft the narrative of a draft STR or SAR made from a case reports.draft and entities.view_pii 200
GET /api/v1/rules/{id}/ai-tuning The latest tuning suggestions for a rule, and whether the assistant can be asked rules.view 200, or 404
POST /api/v1/rules/{id}/ai-tuning Ask the assistant how a rule is doing and what would be worth testing rules.author 200

A support session can read the settings and can never read or ask for a review, a case summary or a narrative draft, nor start or read a batch or call /api/v1/ai/available. With the configuration scope it can read a rule’s tuning suggestions, which hold no customer data, and can never ask for them.

Terminal window
curl -s -b ~/.sp-cookies https://speculapro.yourbank.com.gh/api/v1/ai/settings
{
"enabled": true,
"key_source": "own",
"model": "",
"auto_review": false,
"provider": "anthropic",
"has_own_key": true,
"installation_key": false,
"gateway": false,
"default_model": "claude-sonnet-5-5",
"models": [
{ "id": "claude-sonnet-5-5", "name": "Claude Sonnet 5.5" },
{ "id": "claude-haiku-5-5", "name": "Claude Haiku 5.5" },
{ "id": "claude-opus-5-5", "name": "Claude Opus 5.5" }
],
"providers": [
{ "id": "anthropic", "name": "Anthropic (Claude)", "choose_model": true, "needs_base_url": false },
{ "id": "openai", "name": "OpenAI", "choose_model": false, "needs_base_url": false },
{ "id": "google", "name": "Google (Gemini)", "choose_model": false, "needs_base_url": false },
{ "id": "mistral", "name": "Mistral", "choose_model": false, "needs_base_url": false },
{ "id": "custom", "name": "Another OpenAI-compatible API", "choose_model": false, "needs_base_url": true }
],
"installation_provider": "anthropic",
"monthly_calls": 0,
"topup_calls": 0,
"can_request_more": false,
"calls_on_installation_key": 0,
"usage": [
{ "feature": "alert_review", "model": "claude-sonnet-5-5", "key_source": "own", "calls": 42, "input_tokens": 61230, "output_tokens": 9870 }
],
"reviewed_30d": 30,
"agreed_30d": 24,
"updated_at": "2026-10-12T09:30:00Z"
}
Field Type Meaning
enabled boolean The assistant may be asked about this workspace’s alerts. false until someone switches it on
key_source string Whose API key is used: installation (the operator’s, metered for the workspace) or own (the workspace’s)
model string The model the workspace chose. Empty uses default_model; with a provider other than anthropic on the workspace’s own key it is that provider’s id for the model and is never empty
auto_review boolean The worker reviews new open alerts without being asked
provider string With key_source own: whose API the key is for, anthropic, openai, google, mistral or custom. Always anthropic with key_source installation, where installation_provider applies instead
base_url string With provider custom: the address of the OpenAI-compatible API. Omitted otherwise
has_own_key boolean A key of the workspace’s own is stored. The key itself is never returned
installation_key boolean The installation has a key this workspace can use: SP_AI_API_KEY is set and the plan doesn’t leave it out. When false, only own is accepted. A workspace that is enabled on installation while this is false can’t be answered
gateway boolean The installation’s provider is Claude and it has its own address for calls (SP_AI_BASE_URL). Calls on the installation’s key and on a workspace’s own Claude key go through it; calls to another provider with the workspace’s own key do not. false when the installation’s provider is not Claude: its address is then that provider’s, and a workspace’s own Claude key goes straight to the Claude API
default_model string The installation’s default (SP_AI_MODEL)
models array The Claude models a workspace can choose, each with id and name
providers array The providers a workspace can bring its own key for: id, name, choose_model (the model is picked from models; otherwise its id is typed) and needs_base_url
installation_provider string Whose API the installation’s key is for (SP_AI_PROVIDER)
monthly_calls integer Calls the workspace may make on the installation’s key this calendar month: its plan’s number or the installation’s default (SP_AI_MONTHLY_CALLS), plus topup_calls. 0 is no limit
topup_calls integer Of those, calls the provider added for this month. They don’t carry over. 0 where no limit applies
can_request_more boolean POST /api/v1/ai/allowance-requests is available: a limit above 0 applies (the plan includes the installation’s key), the installation runs a provider console and it has a key
allowance_request object The workspace’s latest request for more calls, whatever its state; omitted if none was ever sent or no limit applies. See Asking for more calls
calls_on_installation_key integer Calls made on the installation’s key this month
usage array This calendar month (UTC), one entry per feature, model and key: calls, input_tokens, output_tokens. A call is counted before it is made, so calls includes calls that failed at the provider; tokens are added when an answer comes back
reviewed_30d integer Alerts the assistant advised on in the last 30 days whose outcome is now known
agreed_30d integer Of those, how many a person then handled the way it advised
updated_at time When the settings last changed; omitted if they never have

How the two agreement figures are counted:

  • Only the latest review of each alert counts, and only when it recommended likely_false_positive or needs_investigation.
  • An alert that went into a case agrees with needs_investigation.
  • An alert closed as false_positive or no_action agrees with likely_false_positive.
  • Alerts closed as duplicate, and alerts still open, are left out.

The figure says how often people followed the advice, not how often the advice was right.

Replaces the settings. Send every field each time.

Terminal window
curl -s -b ~/.sp-cookies -X PUT https://speculapro.yourbank.com.gh/api/v1/ai/settings \
-H "Content-Type: application/json" \
-H "X-Change-Reason: Pilot%20of%20the%20assistant%20on%20AML%20alerts" \
-d '{
"enabled": true,
"key_source": "own",
"model": "",
"auto_review": false,
"api_key": "sk-ant-EXAMPLE-not-a-real-key"
}'
Field Required Meaning
enabled Yes Switch the assistant on or off
key_source Yes installation or own
model No With Claude: one of the ids in models, or empty for the default. With provider openai, google, mistral or custom: required, the model’s id as the provider names it, up to 120 characters (letters, digits and . _ : / @ -, starting with a letter or digit). It isn’t checked against the provider
auto_review No Review new alerts automatically. Needs enabled
provider No With key_source own: anthropic (the default when left out), openai, google, mistral or custom. Ignored and saved as anthropic with key_source installation
base_url With custom The address of an OpenAI-compatible API, normally ending in /v1; calls go to <base_url>/chat/completions. At most 500 characters; a trailing / is dropped. It must be https and public unless the installation allows otherwise (SP_CONNECTOR_ALLOW_PRIVATE, SP_CONNECTOR_ALLOW_HTTP), with no user name or password, no ?query and no #fragment. A path is allowed and /v1 is not enforced. Sent with key_source own and any other provider, it is refused with 422; with key_source installation it is ignored
api_key No The workspace’s own key, at most 400 characters. Write-only: it is stored encrypted and never returned. Leave the field out to keep the stored key; send an empty string to remove it. Required when the workspace is on its own key and provider or base_url changes

The answer is 200 with enabled, key_source, model, auto_review, provider and, for custom, base_url as saved.

Answer Meaning
422 the key is the installation's or the workspace's own key_source is neither installation nor own
422 "…" is not a model this installation offers With key_source installation: model isn’t in models, or the installation’s key is for a provider other than Claude (send it empty)
422 "…" is not a Claude model the assistant offers With key_source own and provider anthropic: model isn’t in models
422 "…" is not a provider the assistant can use An unknown provider. A value outside the list is normally refused earlier, as 422 validation failed
422 give the model's id as the provider names it (letters, digits and . _ : / @ -) A provider other than anthropic with no model, or one with other characters
422 give the API's address, such as https://models.example.com/v1 provider custom and base_url is missing or has no host
422 the API's address must start with https:// Another scheme. Plain http is accepted only where the installation allows it (SP_CONNECTOR_ALLOW_HTTP)
422 the API's address can't carry a user name or password; the key goes in its own field https://user:secret@…
422 the API's address can't carry a ? or a #: it is the base the calls are added to, usually ending in /v1 A query string or a fragment
422 the API's address is on a network this installation does not let workspaces reach An internal or private host, unless the installation allows it (SP_CONNECTOR_ALLOW_PRIVATE). The host is checked again each time it is dialled
422 an API address is only for another OpenAI-compatible API base_url sent with key_source own and a provider other than custom
422 the stored key was given for another provider or address; enter the key for this one On the workspace’s own key, provider or base_url differs from what is saved and no api_key was sent
422 this installation has no AI key of its own; use your workspace's key key_source is installation and the installation has no key
422 automatic review needs the assistant switched on auto_review is true with enabled false
422 give the workspace's API key to switch the assistant on with it enabled with key_source own, and no key stored or sent

The key is not tried when you save it. A key the provider refuses shows up on the first review, as 502.

A change falls under the action type ai.settings (AI assistant), which requires a second person by default, when at least one of these is true:

  • enabled goes from false to true;
  • auto_review goes from false to true;
  • key_source changes;
  • provider changes, or base_url changes while provider is custom: either sends data somewhere else;
  • model changes;
  • the request carries api_key (any value, including an empty string that removes the key).

The last four count whether the assistant is on or off: they decide what the next switch-on would use. A request that does nothing but switch the assistant off, stop automatic review, or both, applies at once and answers 200, with no reason needed.

For a gated change, PUT answers as every gated endpoint does:

  1. Without a reason: 428 Reason required. The settings are checked first, so invalid ones get their 422 here.
  2. With an X-Change-Reason header: 202 Accepted, with the pending request in change_request. Nothing has changed yet. Someone else with settings.approve approves it, and the settings are saved then. A key sent with the request is stored encrypted while it waits.

See Change requests API for the full exchange, polling and expiry. The request’s summary names the provider when it isn’t Claude, and the address for custom: AI assistant on, using the workspace’s own API key for custom at https://models.example.com/v1.

Asks the service provider for more calls on the installation’s key for the current calendar month. Nothing changes until the provider answers: calls it adds are available at once and do not carry over. It is not a settings change and needs no approval.

Terminal window
curl -s -b ~/.sp-cookies -X POST https://speculapro.yourbank.com.gh/api/v1/ai/allowance-requests \
-H "Content-Type: application/json" \
-d '{ "calls": 500, "note": "A backlog of alerts to clear before quarter end." }'
Field Required Meaning
calls Yes How many more calls this month, 1 to 1,000,000
note No Why, for whoever answers. At most 1,000 characters. The provider’s staff read it as written; they are not shown who asked
{
"id": "01a133e9-4c63-74a3-9e24-3522780eb136",
"calls": 500,
"note": "A backlog of alerts to clear before quarter end.",
"status": "pending",
"granted_calls": 0,
"decision_note": "",
"created_at": "2026-10-13T06:18:09Z"
}

The same object is allowance_request in GET /api/v1/ai/settings. status becomes granted (with granted_calls, which may differ from calls), declined, or expired when the request was left unanswered at the end of its month (worked out when read; a new request can then be sent); decision_note is the provider’s answer and decided_at when it was given.

Answer Meaning
403 missing permission settings.manage The caller can’t manage settings
409 a request for more AI calls is already waiting for an answer One request can wait at a time. A request left unanswered from an earlier month does not count: it reads expired and a new one can be sent (the stored row is then closed as declined, with the answer Not answered in the month it was asked for.). A waiting request can’t be withdrawn
409 more calls can't be asked for from here: this installation's administrator sets the allowance No limit applies to the workspace, its plan does not include the installation’s key (limit 0), the installation runs no provider console, or it has no key. can_request_more is false
422 calls or note outside the limits, or an API key instead of a signed-in person

The audit log records ai.allowance_request with the number asked for. The provider’s answer arrives as provider.ai_topup or provider.ai_request_declined, and as a notification to everyone with settings.manage. A support session can’t call this endpoint.

Past the allowance, every endpoint that asks the assistant answers 429 this month's AI allowance is used up on the installation’s key.

The latest review of the alert, and whether the assistant can be asked.

Terminal window
curl -s -b ~/.sp-cookies \
https://speculapro.yourbank.com.gh/api/v1/alerts/0192f3d0-aaaa-7000-8000-000000000010/ai-review
{
"available": true,
"review": {
"id": "0192f3d0-bbbb-7000-8000-000000000020",
"recommendation": "likely_false_positive",
"confidence": "medium",
"summary": "Customer A made four cash deposits under the threshold in 48 hours. Two earlier alerts of the same kind were closed as false positives.",
"reasons": ["4 cash deposits totalling 19,400.00 GHS, in line with 48,200.00 GHS received over 90 days"],
"checks": ["Confirm the declared source of the cash"],
"model": "claude-sonnet-5-5",
"automatic": false,
"requested_by": "Efua Mensah",
"created_at": "2026-10-12T10:02:11Z",
"out_of_date": false,
"superseded": false,
"withheld": false
}
}
Field Type Meaning
available boolean The assistant is switched on for this workspace. false too after a move to another region, until it is switched on again there
review object The latest review; omitted when the alert has none. A review stays readable after the assistant is switched off and after the alert is closed
review.recommendation string likely_false_positive, needs_investigation or insufficient_information
review.confidence string low, medium or high
review.summary string A few sentences, at most 1,200 characters
review.reasons array Up to six strings: what in the alert supports the recommendation
review.checks array Up to four strings: what a person could check next
review.model string The model that answered
review.automatic boolean Reviewed by the worker without being asked
review.requested_by string The name of the person who asked; omitted for an automatic review
review.created_at time When the review was made
review.out_of_date boolean The alert has had hits since this review, or superseded is true
review.superseded boolean The review says likely_false_positive and the alert is now held (its subject designated, or its severity raised to critical, since). Always with out_of_date: true. The queue and automatic review ask about such an alert again
review.withheld boolean true when the caller doesn’t hold entities.view: summary is then an empty string and reasons and checks are empty arrays, because the reasoning can mention customer details the caller may not see. The other fields are returned as usual

People and organisations appear in the text as placeholders such as Customer A, never by name.

An alert that doesn’t exist in your workspace answers 404 not found.

Asks the assistant about an open alert. There is no body. The call waits for the model, which takes seconds; allow up to a few minutes before timing out. The answer is 200 with the review object above (without the available wrapper).

Terminal window
curl -s -b ~/.sp-cookies -X POST \
https://speculapro.yourbank.com.gh/api/v1/alerts/0192f3d0-aaaa-7000-8000-000000000010/ai-review

The call is counted in usage before it is made. Each answer is stored as a new review and written to the audit log as ai.alert_review. A caller without entities.view is refused with 403 and no call is made (reading a review someone else asked for still works for them, with withheld: true). Asking again adds another review; the earlier ones are kept. Sanctions alerts, critical alerts and alerts about subjects designated pep, pep_rca or sanctioned, or about an account owned by such a customer (held: true on the alert), are never answered with likely_false_positive: see The guardrail in code.

Answer Meaning What to do
403 the assistant's answer can mention customer details your role may not see (entities.view), so it is not asked on your behalf The caller holds cases.work but not entities.view. No call was made or counted Have someone who can see customers ask
404 not found No such alert in your workspace Check the ID
409 the AI assistant is off for this workspace Nobody has switched it on Switch it on under Settings → AI assistant
409 the AI assistant has no API key to use The chosen key source has no key Store your key, or choose the other source
409 the assistant answered this a moment ago and nothing has changed since; ask again in a few minutes A person asked again within five minutes of a review made at the alert’s present hit count, whether a person or the worker made it Read the review that is there. The wait ends after five minutes or with the alert’s next hit. Not counted
409 only an open alert can be reviewed The alert is in a case or closed Nothing: the earlier review, if any, stays readable
429 this month's AI allowance is used up The workspace reached monthly_calls on the installation’s key Wait for the next calendar month, or use your institution’s own key. Not counted
502 the AI provider refused the API key; check it under Settings, AI assistant The provider answered that the key is not valid or not allowed Replace the key. The call is counted
502 the AI provider could not answer; try again in a moment The provider couldn’t be reached, answered with an error, gave no answer, or answered in an unexpected form Try again. No review was stored, but the call is counted, because the provider may bill it

A summary is for whoever picks a case up: what it is about, the facts that matter and what is still open, with a suggestion of what to do with the case. The suggestion is advice: nothing happens to the case, and closing it or filing a report stays a person’s decision. What is sent is listed under Case summaries.

Permission: cases.view. Answers 404 for an unknown case.

{
"available": true,
"summary": {
"id": "0192f3d0-cccc-7000-8000-000000000001",
"suggestion": "keep_investigating",
"confidence": "medium",
"suggestion_reasons": ["Seven deposits just under the threshold in eight days, and nothing in the data explains them."],
"summary": "Customer A has two open AML alerts for cash deposits just under the reporting threshold…",
"key_points": ["Seven deposits between 9,200.00 and 9,900.00 GHS from 2 to 9 October."],
"open_questions": ["The source of the cash is not in the data."],
"model": "claude-sonnet-5-5",
"requested_by": "Efua Mensah",
"created_at": "2026-10-12T09:14:02Z",
"out_of_date": false,
"superseded": false,
"withheld": false
}
}
Field Type Meaning
available boolean The assistant is switched on for this workspace (false too after a move to another region, until it is switched on again there)
summary object The latest summary; omitted when the case has none
summary.suggestion string likely_false_positive, consider_report, keep_investigating or insufficient_information. Omitted on a summary written before suggestions existed. Returned to every caller, including one without entities.view
summary.confidence string low, medium or high: the model’s own estimate. Omitted with suggestion; an answer with any other value is stored as low
summary.suggestion_reasons array of strings Up to four facts from the data that support the suggestion, each at most 400 characters. When SpeculaPro replaced the suggestion (see below), its own sentence comes first, so there can be five
summary.summary string One short paragraph, at most 1,500 characters
summary.key_points array of strings Up to six facts from the data
summary.open_questions array of strings Up to four things the data doesn’t answer
summary.model string The model that answered
summary.requested_by string The person who asked. A summary is never automatic
summary.created_at date-time When it was written
summary.out_of_date boolean The case has more alerts, hits and timeline entries than when the summary was written, or superseded is true
summary.superseded boolean The summary suggests likely_false_positive and the case is now held: a sanctions case, critical, about a held subject, or holding a held alert. Always with out_of_date: true
summary.withheld boolean true for a caller without entities.view: summary is then "" and suggestion_reasons, key_points and open_questions are empty. suggestion and confidence are still returned

The suggestion is checked in code. If the model answers likely_false_positive for a case whose kind is sanctions, whose priority is critical, whose subject is held (a pep, pep_rca or sanctioned designation in force on it or, for an account, on its owner), or which holds any alert with held: true, SpeculaPro stores keep_investigating with high confidence and puts its own sentence first in suggestion_reasons. The check runs when the summary is written; a stored summary is not rewritten when the subject is designated later. An answer whose suggestion is not one of the four values is refused with 502 and nothing is stored. See What it never suggests.

Case objects from GET /api/v1/cases carry the latest summary’s suggestion as ai_suggestion, without the staleness check.

Permission: cases.work and entities.view. No body. Works on open and closed cases. Answers 200 with the summary object above. The call is written to the audit log as ai.case_summary (with the suggestion and confidence) and counted under the feature case_summary, against the same monthly allowance as alert reviews.

Answer Meaning Counted
403 the assistant's answer can mention customer details your role may not see (entities.view), so it is not asked on your behalf The caller doesn’t hold entities.view. No call is made No
404 not found No such case No
409 the AI assistant is off for this workspace Off, or its settings were saved in another region No
409 the AI assistant has no API key to use The key the settings name isn’t there No
409 the assistant answered this a moment ago and nothing has changed since; ask again in a few minutes A summary less than five minutes old exists and the case has had no alert, hit or timeline entry since No
429 this month's AI allowance is used up The workspace reached monthly_calls on the installation’s key No
502 the AI provider refused the API key; check it under Settings, AI assistant The provider didn’t accept the key Yes
502 the AI provider could not answer; try again in a moment The provider couldn’t be reached or answered in an unexpected form. No summary was stored Yes

The assistant drafts the narrative of an STR or SAR that is still a draft and was made from a case. The draft is a suggestion kept beside the report: neither endpoint changes the report. To use a draft, put its text in reason with PATCH /api/v1/reports/{id}, as for any narrative. What is sent is listed under Report narrative drafts.

Both endpoints need reports.draft and entities.view_pii, like every other report endpoint, because a draft names the customer. Without entities.view_pii the answer is 403 reports contain customer identity; you need entities.view_pii.

{
"available": true,
"draft": {
"id": "0192f3d0-dddd-7000-8000-000000000001",
"narrative": "This report concerns Kwame Asante, a retail customer. Between 2 and 9 October 2026 seven cash deposits were made to account [number]…",
"gaps": ["The customer's stated source of the cash is not in the data."],
"model": "claude-sonnet-5-5",
"requested_by": "Efua Mensah",
"created_at": "2026-10-13T09:14:02Z"
}
}
Field Type Meaning
available boolean A draft can be asked for: the assistant is on for this workspace, and the report is an STR or SAR, still a draft, made from a case
draft object The latest draft; omitted when the report has none. A report’s drafts are deleted when it leaves draft (sent for approval, or voided), so from then on the answer is available: false with no draft
draft.narrative string The suggested text, at most 4,000 characters, with the names put back. Identifying numbers were never sent and appear as [number]
draft.gaps array of strings Up to six things the model could not know and a person must add
draft.model string The model that answered
draft.requested_by string The person who asked. A draft is never automatic
draft.created_at date-time When it was written

Answers 404 not found for an unknown report.

No body. Answers 200 with the draft object above. The call is written to the audit log as ai.narrative_draft on the report (never the text) and counted under the feature narrative_draft, against the same monthly allowance as alert reviews. Each request stores a new draft; the earlier ones are kept and the latest is returned by GET.

Answer Meaning Counted
403 reports contain customer identity; you need entities.view_pii The caller holds reports.draft but not entities.view_pii No
404 not found No such report No
409 the assistant drafts the narrative of an STR or SAR that is still a draft and was made from a case The report is a CTR, has left draft, or was not made from a case No
409 the AI assistant is off for this workspace Off, or its settings were saved in another region No
409 the AI assistant has no API key to use The key the settings name isn’t there No
409 the assistant answered this a moment ago and nothing has changed since; ask again in a few minutes The report’s latest draft is less than five minutes old, whoever asked for it. Unlike alerts and cases, nothing lifts the wait early No
429 this month's AI allowance is used up The workspace reached monthly_calls on the installation’s key No
502 the AI provider refused the API key; check it under Settings, AI assistant The provider didn’t accept the key Yes
502 the AI provider could not answer; try again in a moment The provider couldn’t be reached, or answered in an unexpected form or with an empty narrative. No draft was stored Yes

The assistant reads a rule’s live version and counts of what became of its alerts over the last 90 days, and answers with an assessment and up to four changes worth testing. Neither endpoint changes the rule: a suggestion is tried with the Backtesting API and becomes a new version only through POST /api/v1/rules/{id}/versions and its approval. What is sent is listed under Rule tuning suggestions: the rule and counts, no customer.

Needs rules.view.

{
"available": true,
"advice": {
"id": "0192f3d0-eeee-7000-8000-000000000001",
"assessment": "Nine of the 14 decided alerts were closed as false positives…",
"suggestions": [
{
"change": "Test min_count at 4 instead of 3.",
"why": "Among the hits whose alerts were closed as false positives, cash_in_count_48h has a median of 3.",
"risk": "The earliest hits of alerts that went to cases would no longer fire."
}
],
"cautions": ["14 decided alerts is a small sample."],
"rule_version": 3,
"model": "claude-sonnet-5-5",
"requested_by": "Kwesi Appiah",
"created_at": "2026-10-13T09:14:02Z",
"out_of_date": false
}
}
Field Type Meaning
available boolean The assistant is on for this workspace, the rule has a live version, and its category is not designations (the rule packs’ rules about sanctioned and politically exposed parties), sanctions or screening. It doesn’t say whether the rule has enough history: that is checked when you ask
advice object The latest answer; omitted when the rule has none
advice.assessment string How the rule is doing, at most 1,200 characters
advice.suggestions array Up to four objects with change (what to test), why (the figures behind it) and risk (what it could miss). Empty when the figures support no change
advice.cautions array of strings Up to four things the figures cannot show
advice.rule_version integer The live version number that was read
advice.model string The model that answered
advice.requested_by string The person who asked. Never automatic
advice.created_at date-time When it was written
advice.out_of_date boolean The rule’s live version number is now higher than rule_version

Answers 404 not found for an unknown rule. A support session with the configuration scope can read this endpoint.

Needs rules.author. No body. Answers 200 with the advice object above. The call is written to the audit log as ai.rule_tuning on the rule and counted under the feature rule_tuning, against the same monthly allowance as the other features. Each request stores a new answer; GET returns the latest. A support session can’t call it.

Answer Meaning Counted
404 not found No such rule No
409 the rule has no active version to look at Nothing is live for this rule No
409 the assistant does not suggest changes to sanctions rules: what they must catch is set by law, not by how past alerts were closed The rule’s category is designations, sanctions or screening No
409 fewer than 10 of this rule's alerts in the last 90 days have been decided: too few to suggest anything Fewer than ten alerts with hits of this rule in the period have left the queue No
409 the AI assistant is off for this workspace Off, or its settings were saved in another region No
409 the AI assistant has no API key to use The key the settings name isn’t there, or the workspace’s plan doesn’t include the installation’s key No
409 the assistant answered this a moment ago and nothing has changed since; ask again in a few minutes The latest answer is about the same live version (or a newer one) and is less than five minutes old No
429 this month's AI allowance is used up The workspace reached its monthly allowance on the installation’s key No
502 the AI provider refused the API key; check it under Settings, AI assistant The provider didn’t accept the key Yes
502 the AI provider could not answer; try again in a moment The provider couldn’t be reached, or answered in an unexpected form or without an assessment. Nothing was stored Yes

A batch asks the assistant about many alerts or cases at once. It queues the work and returns at once; the worker then takes the items four at a time. Each answer lands where a single answer does (the alert’s review, the case’s summary), is audited and counted like a single one, and changes nothing on the alert or case. A batch never closes anything.

Permission: cases.work and entities.view.

Field Required Values
kind Yes alert_review (advice on open alerts) or case_summary (a summary and suggestion on cases)
ids One of the two Up to 200 alert or case IDs. Repeated IDs are queued once
unadvised One of the two true: take everything without current advice, up to 200

Send ids or unadvised: true, never both and never neither.

With unadvised, the batch takes:

  • for alert_review: open alerts with no review, or with hits since their latest review, most severe first (critical, high, medium, low), then the most recent activity;
  • for case_summary: cases that are not closed and not awaiting approval and have never been summarised, by priority (critical first), then the soonest deadline. A case whose summary is out of date is not taken.

An alert or case already waiting in another batch is left out.

Terminal window
curl -s -b ~/.sp-cookies -X POST https://speculapro.yourbank.com.gh/api/v1/ai/batches \
-H 'Content-Type: application/json' -d '{"kind":"alert_review","unadvised":true}'
{
"id": "0192f3d0-ffff-7000-8000-000000000001",
"kind": "alert_review",
"total": 40,
"queued": 40,
"running": 0,
"done": 0,
"skipped": 0,
"failed": 0,
"finished": false,
"created_at": "2026-10-13T09:14:02Z"
}
Field Type Meaning
id UUID The batch
kind string alert_review or case_summary
total integer How many alerts or cases the batch holds
queued, running integer Waiting, and being read now
done integer Answered
skipped integer Not asked: it already had current advice, was no longer open, was not found, was answered less than five minutes ago, or nothing more could be asked (see last_reason). A skipped item is not counted against the allowance, except the one item on which the provider refused the key
failed integer The call was made and failed. Counted against the allowance like any failed call
last_reason string Why the latest item was skipped or failed; omitted when none was
finished boolean Nothing is waiting or running
created_at time When the batch was asked for
Answer Meaning
403 missing permission cases.work The caller can’t work cases
403 the assistant's answer can mention customer details your role may not see (entities.view), so it is not asked on your behalf The caller doesn’t hold entities.view
409 the AI assistant is off for this workspace, 409 the AI assistant has no API key to use Said at once, not on every item
409 there is nothing to ask the assistant about: everything in the queue already has its advice, or is already being looked at Nothing was queued: with unadvised, nothing lacks advice; with ids, every one that could be asked about is already waiting in a batch
422 none of the alerts or cases named can be asked about: they are not in this workspace, or the alerts are no longer open With ids: none of them is an open alert (or a case) of this workspace. When only some are, those are left out without a message and total is smaller than the list sent
422 name up to 200 alerts or cases, or ask for everything without advice Both ids and unadvised, neither, or more than 200 IDs

How a batch runs:

  • The allowance is checked on each item, not when the batch starts. A batch of 200 can use 200 calls. When the allowance runs out, the assistant is switched off, the key is missing or the provider refuses the key, the items still waiting are marked skipped with that reason.
  • Three provider failures in a row stop a batch. The items still waiting are skipped with the AI provider failed three times in a row: …. The failed calls are counted. Each worker process keeps its own count in memory, so with several workers a batch can fail a few more times before it stops.
  • Named IDs are filtered when the batch is queued. Only open alerts (for alert_review) or existing cases (for case_summary) of this workspace are queued; the others are left out silently, so total can be smaller than the number of IDs sent.
  • Each answer is recorded as asked by the person who started the batch. Before each item the worker checks that this person’s account is still active and still holds cases.work and entities.view; if not, the rest is skipped with the person who asked may no longer ask the assistant. Signing out does not stop a batch.
  • A workspace that is suspended or being moved to another region has its batches paused.
  • A worker that is stopping still records what became of the items it held. An item left running by a worker that died is taken again after ten minutes: if the first attempt had called the provider but not stored the answer, the second attempt is a second counted call; if the answer was stored, the second attempt is skipped as already advised.
  • Finished items are deleted seven days after they finish; after that the batch answers 404.

Permission: cases.work. The batch object above: counts only, no alert or case IDs. A batch is readable only by the person who started it. 404 not found for an unknown batch, someone else’s batch, or one whose items have all been deleted.

Permission: cases.work. kind is required. Returns the caller’s most recent batch of that kind as {"batch": {…}}, or {} when they have asked for none in the last week. The queue pages use it to show progress again after a reload.

Permission: alerts.view or cases.view. Returns {"available": true} when the assistant is switched on for the workspace, and nothing else about its settings.

Alert objects from GET /api/v1/alerts and GET /api/v1/alerts/{id} carry ai_recommendation when the assistant has advised on the alert since its last hit. It is omitted when there is no review, when the review is out of date, and when the review says likely_false_positive but the alert is now held.

GET /api/v1/alerts takes ai= to list only alerts with a given current recommendation, or ai=none for alerts with no current advice. See GET /api/v1/alerts.

Closing alerts is never done by the assistant. A person can close several at once with POST /api/v1/alerts/close.