The Mistral AI Batch API

Half the price, because you gave up the one thing a synchronous call guarantees: an answer, now, that you can see fail. The batch discount is real β€” and it evaporates row by row every time a job finishes successfully with your data missing from it.

β€’14 min read
Staff Pick

πŸ“‘ Monitor your APIs β€” know when they go down before your users do

Better Stack checks uptime every 30 seconds with instant Slack, email & SMS alerts. Free tier available.

Start Free β†’

Affiliate link β€” we may earn a commission at no extra cost to you

There is a version of Mistral AI that costs roughly half as much, and the only price is that you stop finding out immediately whether it worked. The Batch API takes a file of requests, hands you a job id, and completes the whole set within a window measured in hours. For anything that does not need an answer inside a request timeout β€” classifying a backlog, embedding a corpus, re-scoring a table overnight β€” that is an obvious trade, and the discount is genuine.

It is also where teams lose money they think they are saving. The synchronous API fails loudly: an exception, a status code, a stack trace pointing at the line that broke. Batch fails quietly. A job reaches completed, you fetch the output, and it has nine hundred and forty rows where you submitted a thousand. No error was raised. Nothing in your telemetry moved. The sixty missing rows are not an outage β€” they are the normal, documented behaviour of a system where every request inside the batch succeeds or fails on its own.

This guide is about the gap between the job finished and every input got an answer. That gap is where the batch discount is either kept or quietly handed back, and closing it is almost entirely a matter of how you submit and reconcile, not how you call the model.

What the Batch Contract Actually Promises

Read the guarantees literally, because the difference between what batch promises and what teams assume it promises is exactly the set of failures you will spend a quarter debugging.

PropertyWhat you actually getWhat that forces you to build
CompletenessThe job finishes; individual rows may notReconcile output ids against input ids on every job. Never trust the terminal status alone.
LatencyA completion window in hours, no position inside itTreat completion as an event, never a deadline. Keep a synchronous escape hatch for urgent rows.
OrderingResults keyed by your id, not by submission orderPut a stable custom id on every line. Join on it; never match by row position.
Pricing~50% off, on successfully processed tokensTrack delivered-token cost, not quoted price. Re-runs and synchronous retries erode the discount.
Result availabilityOutput file retained for a limited windowFetch and persist results promptly. Do not treat the provider as your archive.

Every one of those rows is a thing you handle or a thing that silently costs you. There is nothing exotic here β€” it is the standard shape of every batch inference system in the industry β€” but the synchronous API trained your instincts to expect guarantees this contract does not make.

The Lifecycle, and Where Each Stage Drops Work

A batch moves through four stages, and each one has a characteristic failure that returns success somewhere while losing your data.

Upload. You send a file of requests, one per line, each with a custom id. The failure here is a single malformed line taking down more than itself, or an encoding issue that shifts every id by one. Validate the file locally before you upload it β€” count the lines, assert every id is unique and present β€” because a bad input file is far cheaper to catch on your side than to diagnose from a job that processed nine hundred rows and errored on the rest.

Submit. You create the job pointing at the uploaded file and receive a job id. The failure is losing that job id: your process crashes, or the submit succeeds but the response never reaches you, and now a job is running that nothing is waiting for. Persist the job id transactionally the moment you have it, before you do anything else, and record the input id set alongside it so you know exactly what this job was supposed to return.

Wait. The job sits in a queue you cannot see. The failure is treating this stage as instantaneous or bounded β€” blocking a request on it, or giving up too early and re-submitting a job that was merely slow, doubling your cost. Poll on a schedule, list your non-terminal jobs, and advance state in your own database from the authoritative job object rather than from any push you may or may not receive.

Retrieve and reconcile. The job is done; you fetch the output. This is the stage everyone under-builds. Pull the results, key them by your custom id, and compute the set difference against the input ids you stored at submit time. The rows in that difference are your failures. Route them to a synchronous retry, a dead-letter table, or a human β€” but route them somewhere, because a completed job with an unreconciled output is exactly how sixty rows vanish without a trace.

The Custom ID Is the Whole Game

If you take one thing from this guide, take this: every line in the input file carries a custom id that you can join back to your own data without a side table, and every downstream decision keys off it.

The results do not come back in submission order. They can arrive interleaved, some rows can be absent entirely, and a partial job returns a subset. If you match answers to inputs by line position β€” row three of the output is the answer to row three of the input β€” the first missing row shifts every subsequent match by one, and you will confidently write the wrong model output against the wrong record for the entire tail of the file. That is worse than losing the rows, because it is silent and it is wrong rather than absent.

With a stable id, matching is a join and reconciliation is a set-difference. Missing rows announce themselves. Duplicate deliveries collapse. A re-run of just the failures slots back into the same keyspace. The id is the cheapest insurance in the whole pipeline, and it is the single most common thing teams leave out on the first integration and add back after their first silent data loss.

When Batch Is the Wrong Tool

The discount is seductive enough that teams push work into batch that has no business being there. Batch is wrong whenever a human or a request is waiting on the answer, because you cannot promise when it lands. It is wrong for small volumes where the setup, upload, poll and reconcile overhead outweighs the token savings on a few hundred rows. And it is wrong as the only path for anything, because a provider incident on the batch queue is close to invisible from inside your telemetry β€” no errors, no latency spike, just a queue that stops draining and a graph that flattens into what looks like a quiet afternoon.

Keep a synchronous path alive for the rows that cannot wait, and monitor api.mistral.ai independently so that β€œthe batch queue is stuck” reaches you as an alert rather than as a support ticket three hours after the job should have finished.

What to Instrument

Five numbers turn batch from a black box into something you can reason about: the age of your oldest non-terminal job against the promised window; the submitted-versus-returned row count for every job; the count of rows routed to synchronous retry because batch dropped them; the delivered-token cost per batch, so you know the real discount rather than the quoted one; and the count of jobs re-submitted because a slow one was mistaken for a dead one. The first two catch silent data loss. The last three tell you whether the batch discount is actually money in the bank or an accounting fiction that your retries have already spent.

What none of those can tell you is whether api.mistral.ai was degraded while your queue sat quiet. That failure is invisible from inside a system that was waiting rather than calling, and it is precisely the gap external monitoring closes.

Frequently Asked Questions

How much does the Mistral AI Batch API actually save?

The headline is roughly half the per-token price of the equivalent synchronous call, and that number is real, but it is a ceiling rather than the figure you should budget against. You realise the full discount only when the job runs once, returns every row, and needs no re-submission. Every row that comes back with an error you still have to serve synchronously, every partial job you re-run, and every result you fetch twice because the first fetch was lost erodes the gap. Treat 50% as the best case and instrument the actual delivered-token cost per batch, because the number that matters is what you paid to get usable answers, not what the price sheet quoted.

How long does a Mistral batch job take to finish?

There is no latency you can promise a caller, and that is the entire trade. The provider commits to completing the job within a window measured in hours, not to any particular position inside it, and the same batch submitted at two different times can finish in twenty minutes or near the deadline depending on queue depth you cannot see. Design every downstream consumer to treat completion as an event that arrives whenever it arrives, never as a deadline you schedule around. If a specific row needs an answer inside a request timeout, it does not belong in a batch -- send it synchronously and pay full price for that one row.

A batch reports completed but I got fewer results than I submitted. Is that a bug?

No -- it is the single most important thing to understand about batch inference. A job reaching a terminal completed state means the job is done, not that every request inside it succeeded. Individual rows fail independently: a malformed message, a row that trips a length limit, a transient model error on one line. Those show up in an error output, or simply as an absent id in the results, while the job itself is marked a success. If your code assumes completed means every input has a matching output, it will silently drop the failures and you will not notice until a customer asks where their record went. Reconcile by input id, not by job status.

Should I poll the batch job or wait for a callback?

Poll, and treat any callback as an accelerator rather than the source of truth. A scheduled sweep that lists non-terminal jobs and asks the API for their current state is the only mechanism that still works when a webhook is dropped, when your receiver was deploying at the moment of delivery, or when the job was submitted by a different process than the one waiting for it. Build the poll first, make it idempotent, and let it be the thing that actually advances a job to done in your database. A push, if one exists, just means the poll finds the answer sooner.

What is the safest way to structure the input file?

Put a custom id you control on every single line, and make it something you can join back to your own database without a lookup table you might lose. The results come back keyed by that id and, crucially, not necessarily in the order you submitted, so if you relied on line position to match answers to inputs you will misassign every row after the first gap. A stable per-row identifier turns matching into a join and makes partial failure a set-difference you can compute rather than a mystery you investigate.

How do I know if a batch is stuck versus just slow?

From inside your own application you frequently cannot, because a batch that is queued behind a provider-side incident looks identical to one that is merely far back in a healthy queue -- both are simply not done yet, with no error to catch and no latency metric moving. The signal is the age of your oldest non-terminal job measured against the completion window you were promised. When that age crosses the window, you have crossed from slow into stuck, and that is the moment to fail over the time-sensitive portion to synchronous calls rather than keep waiting on a job that may never land.

Related Guides

A Stalled Batch Queue Looks Exactly Like a Quiet Day

When the batch path degrades, your telemetry goes quiet rather than red β€” no errors, no latency spike, just jobs that never reach done. API Status Check probes api.mistral.ai independently and alerts on errors and latency, so you find out from a monitor instead of from a customer asking where their export went.

Start Your Free Trial β†’

πŸ›  Tools We Use & Recommend

Tested across our own infrastructure monitoring 200+ APIs daily

Better StackBest for API Teams

Uptime Monitoring & Incident Management

Used by 100,000+ websites

Monitors your APIs every 30 seconds. Instant alerts via Slack, email, SMS, and phone calls when something goes down.

β€œWe use Better Stack to monitor every API on this site. It caught 23 outages last month before users reported them.”

Free tier Β· Paid from $24/moStart Free Monitoring
1PasswordBest for Credential Security

Secrets Management & Developer Security

Trusted by 150,000+ businesses

Manage API keys, database passwords, and service tokens with CLI integration and automatic rotation.

β€œAfter covering dozens of outages caused by leaked credentials, we recommend every team use a secrets manager.”

SEMrushBest for SEO

SEO & Site Performance Monitoring

Used by 10M+ marketers

Track your site health, uptime, search rankings, and competitor movements from one dashboard.

β€œWe use SEMrush to track how our API status pages rank and catch site health issues early.”

From $129.95/moTry SEMrush Free
View full comparison & more tools β†’Affiliate links β€” we earn a commission at no extra cost to you