An open door with a blank interior is the large shape, with a balance with one empty pan apart from it.

How published plan rates and credits fit a list run

THE MAILCHECKUP JOURNAL

API rate-limit handling in Node.js, for a MailCheckup list run, starts from the numbers on the pricing table and from the credit rules, not from a status code you hope to parse. Credits, lists at once, row caps, and a per-minute rate are published. An HTTP 429 body, a rate-limit header, and a REST error schema for "slow down" are not. Check account status before a large run. Verification does not start when available credits are zero. Unknown stays free. This page is how to read that table without inventing the missing schema. Prices and caps below are the published plan figures, checked 6 October 2026.

MAILCHECKUP / BLOG / PLAN RATES AND CREDITS↘

What the pricing table publishes

The pricing page is the source for these figures. Monthly credits expire at the end of the paid period and do not roll over. New workspaces start on Free: 100 credits, expiring about 30 days after signup. Support is a ticket in the app, plus email.

Free is $0, 100 credits, 2 lists at once, 5,000 rows, 30 per minute, support name Community. Starter is $19, 5,000 credits, 10 lists, 50,000 rows, 60 per minute, Standard. Growth is $39, 25,000 credits, 25 lists, 250,000 rows, 120 per minute, Priority. Business is $199, 100,000 credits, 50 lists, 500,000 rows, 240 per minute, Priority. Scale is $449, 500,000 credits, 100 lists, 1,000,000 rows, 300 per minute, Enterprise.

Credit packs do not expire. The published packs are 1,000 for $5, 5,000 for $15, 10,000 for $25, 25,000 for $45, 50,000 for $169, 100,000 for $279, 250,000 for $549, 500,000 for $949, and 1,000,000 for $1,599. A pack is not a second rate column. It adds credits. Do not assume a pack upgrades lists-at-once or the rate. Those columns sit on the plan.

You pay only when the answer is finished. A chargeable result costs one credit. Unknown, a greylist, a blocked check, an unreachable mail server, and a system error cost nothing, and the hold is released. Consumed credits are not refunded. A seven-day voluntary refund window is the published policy direction for purchases. Checkout on the marketing site is not the operational billing system. Purchases happen in the app. Invoices are Secuno LLC, downloaded from Billing after Stripe confirms payment.

If a number you remember is not in the table above, do not ship it.

Read the four columns as four different refusals. Credits answer whether a finished chargeable result can be paid for. Lists at once answer whether another list may open. Rows answer whether this file fits the list. The rate column answers the published per-minute figure you plan around. A run can fail the first and pass the other three. Your notes should say which column stopped you. A single word, quota, hides the fix. Adding a pack does not raise the row cap. Raising the plan is a different purchase from buying a pack.

What a credit is

One credit pays for one finished chargeable result: valid, deliverable, undeliverable, dead, invalid, disposable, catch-all, role account, or mailbox full. Risky is a summary group for disposable, catch-all, role account, and mailbox full. It is not a second charge on top of those codes. If you budget "one credit per risky," you will double-count in a spreadsheet. Budget one credit for the underlying code.

The free results are unknown, retry later, greylisted, MX unreachable, provider blocked, and system error. They are not the same as invalid. Not checked means no finished result yet, and it is free until a chargeable result exists. A cleanup that deletes unknown rows does not refund a credit you never spent, and it destroys the hold you might have wanted to recheck. The results guide is the short table. The unknown versus invalid page is why a free code stays in the file.

Duplicates inside one file are stored once and are not billed twice. Your credit estimate should use unique addresses inside that file, not the raw row count, and then only the ones that finish with a chargeable code. You will not know the free share before the run. Estimate with a range: every unique address chargeable at the top, and a lower figure only if you have your own history. Label history as yours.

A recheck of one group can use another credit because it is a new finished check. Results already saved for the rest of the list stay. Do not budget a recheck as free because the first pass already ran. Unknown or mailbox full can be rechecked without redoing addresses that already have a result. The new chargeable answers are what cost.

System error means the check did not finish and the hold is released. Do not count a system error as a spent credit in your reconciliation. If your ledger and the list's credits field disagree, believe the finished chargeable count, and keep the raw codes so you can add them yourself.

What the rate column is allowed to mean

The rate column is a published per-minute figure on the plan: 30, 60, 120, 240, or 300. It is a planning number beside the plan name. It is not an HTTP status, not a header name, and not a JSON field.

No HTTP 429 schema is published here. Do not write a Node client that switches on a body you invented, a Retry-After value you invented, or an error string you matched from a blog. Named MCP error codes on the product page are list_limit, list_busy, insufficient_credits, list_already_started, and list_importing. insufficient_credits is the credit signal. If you need a branch, branch on the codes that are named, and leave a default that stops and shows the code you actually received. A default that retries forever is not rate handling. It is a loop.

Docs pages that describe limits in general terms are integration principles. They are not a finished REST contract. Idempotency key format, REST base URL, and REST request schema are not finalized there. Do not promote a sentence about "bounded backoff" on a preview page into MailCheckup's webhook retry either. Webhook gaps are fixed. That is a different interface. A list run's per-minute column is a third fact. Keep the three apart in code comments so a future reader does not implement one schedule for all three.

What you may do with the published rate is pace work you initiate. If the plan says 60 per minute, a loop that fires far above that on purpose is ignoring a published number. How the service responds when you ignore it is not specified as a 429 document. Pacing is how you stay near the published figure without pretending you have parsed an unpublished error. Measure completed checks, not request count alone. Unknown results still consumed time. They did not consume a credit.

Flow: Pick a plan; Credits; Rate column; List caps; Stop at zero.
Explain the published plan table: credits, lists at once, rows, and the rate column, without inventing an HTTP 429 body.

Pick the plan, read credits, read the rate column, read list and row caps, and stop when available credits are zero. The flow has no box for an invented status schema.

Lists at once and row caps

Lists at once and the row cap are separate columns from credits and from the rate. Free allows 2 lists and 5,000 rows. Starter allows 10 and 50,000. Growth allows 25 and 250,000. Business allows 50 and 500,000. Scale allows 100 and 1,000,000. A file can fit the row cap and still not fit the credits. A workspace can have credits left and still be unable to open another list because the list cap is full.

A running list can take more addresses. They join the same run. Do not start a second list merely to append. Starting a second list spends a slot against "lists at once," and it splits one audience into two result sets you must reconcile. If you are at the list cap, finish or remove a list you are allowed to remove. Removing, clearing, or deleting is refused while importing or verifying. Stop first.

create_list does not start verification. add_emails takes up to 500 addresses at a time on the MCP tool. That 500 is a tool argument limit, not the plan's per-minute rate and not the row cap. You can add 500 repeatedly until the list's row cap or your credits say stop. verify_emails has a cap of 25, and on this production host verify_email and verify_emails are refused when live stations are required. The tool tells the agent to use a list. Do not build a per-address loop and call it rate-limit handling. The list is the run the plan columns describe.

list_limit in the named errors is the signal to read when a list operation is refused for a limit. Handle it by stopping and reading account status, not by opening ten more clients. Several workers that each look "under the rate" still share one workspace's lists, rows, and credits.

Count open lists before you create one. The plan's lists-at-once number is a cap, not a suggestion. Free at 2 is easy to spend with a test list left behind and a production list beside it. Close or leave the test list before the real file needs the slot. list_limit is the named error to log if creation is refused. Do not respond by generating a new workspace API key. The key is the same workspace, and the cap is the workspace. mck_your_key in a second process does not buy a third Free list.

What happens at zero credits

Call account_status before a large run. Verification does not start when available credits are 0. insufficient_credits is the named error to expect when a start is refused for credits. Do not translate that into invalid addresses. Nothing was checked. The rows stay not checked, which is free until a chargeable result exists.

Zero available credits is also different from a hold. Holds reserve credits in chunks for work in progress. Stopping a run releases unused holds. Consumed credits stay consumed. If account status shows zero available because a hold has reserved them, the fix may be to wait for the run, or to stop it and release the unused portion. Deleting the list while it is verifying is refused. Stop first. Then look again.

A credit pack or a plan change is how you add credits that expired or were never there. Monthly credits do not roll over. A Free workspace's 100 credits expire about 30 days after signup. A run planned for day 31 on the original Free grant is a zero-credit start even if you never spent the 100. Packs do not expire. Put the credits you need for a dated campaign on a pack, or on a period that covers the run, and confirm account status on the day you start.

Do not start a second workspace to dodge a zero balance unless you intend a separate bill and a separate key. The API key is that workspace only. Results do not follow you to another workspace by themselves. There is no published merge. Export and import would be your own join, with your ids intact.

Show the operator the available number from account_status in the same screen as the file's unique count. If available is zero, the button that starts verification should not fire. If available is above zero and below the unique count, say so. The run may still start and then stop when holds cannot cover the rest. That partial finish is allowed. Consumed rows stay. Unused holds release when you stop. Pretending the run will check every row because the file fit the row cap is how a campaign launches on not-checked addresses.

Holds

Holds exist so a run can reserve credits before every row has finished. The product holds in chunks. You should not build a second hold in your application that subtracts the same credits again. Read account status. The available figure already reflects what the service considers spendable.

When a check finishes as chargeable, the credit is consumed. When a check finishes as unknown or another free code, the hold for that check is released and you are not charged. When the check does not finish because of a system error, the hold is released. Your ledger should show three buckets: consumed, released, still held. A single "spent" number that adds all three will not match Billing.

Stopping releases unused holds. It does not refund consumed credits. If you stop halfway, the finished chargeable rows stay billed and stay in the results. The unfinished rows return to a state where the hold is gone. You can add addresses to a running list before you stop. After you stop, a new start is a new run decision. list_already_started is the named error when you try to start a list that has already started. list_busy and list_importing are the named errors when the list is occupied. None of them is a rate-limit header. Back off by waiting for the list, not by inventing a 429 parser. The wait you choose is your poll interval. MCP guidance says to poll get_list and not to wait inside a tool.

An illustrative hold sketch, not a customer ledger: a chunk reserves 1,000 credits, 400 finish chargeable, 100 finish unknown, and you stop. Consumed 400. The unknown and the unused reserve release. If your notes say "the stop refunded 400," the notes are wrong. The 400 were consumed. The release is the part that never finished as chargeable.

Reconcile after the run with three numbers you can add by hand from the result codes. Chargeable finishes should match consumed credits, one each. Free finishes should match a released amount, not a charge. Anything still running is a hold. If you cannot produce those three from the export, do not invent a fourth bucket called rate limited. No such result code is in the results guide. A slow run is still a run. Its codes are the same codes.

A labeled plan choice

This choice is illustrative. It is not a quote and not a measured list. Suppose 12,000 unique addresses in one file, and you will not know how many finish free. The top of the range is 12,000 credits if every result is chargeable. The bottom is unknown until the run. Duplicates inside the file should already have been collapsed in that 12,000. Raw rows were higher. They are the wrong denominator.

Free's 100 credits cannot cover the top of that range, and Free allows 2 lists and 5,000 rows. The file's unique count is already above the Free row cap. Starter's 5,000 monthly credits are below 12,000. Starter's row cap of 50,000 would fit the file. Credits are the constraint in this sketch, not rows. Growth's 25,000 credits sit above 12,000, at $39 for the period, with 25 lists and 250,000 rows, and a published rate of 120 per minute. A pack can cover a gap without a plan change. 10,000 credits for $25 plus Starter's 5,000 monthly credits is an arithmetic illustration of 15,000, which is above 12,000, if the monthly credits are still inside the period and have not been spent. Monthly credits still expire at the end of the period. The pack does not.

Do not turn the sketch into "buy Growth." If your history, labeled as yours, shows a large unknown share, the chargeable count may fit Starter. If the file might be rechecked, budget a second credit for the group you recheck. If you need the result the same hour, read the rate column as a planning pace: 60 per minute on Starter is a different wall-clock sketch than 120 on Growth. It does not know concurrency beyond the published per-minute figure, and it will not invent one.

The check order still applies on every plan. Syntax failures and recipient rejects are chargeable when they are finished chargeable codes. Unknown is free on Free and on Scale. The plan does not change the meaning of the code.

Matrix: Unknown → Free; Chargeable → One credit; Zero credits → Run does not start; HTTP 429 schema → Not published.
Actions stay specific. Unknown is not given the invalid action.

Unknown is free. A chargeable finish is one credit. At zero available credits the run does not start. An HTTP 429 schema is not published, so it is not something you code.

What not to code against a guess

Do not code a REST client against a base URL, a rate-limit header, or a 429 JSON shape this product has not published. account_status, then create_list, then add_emails in batches of at most 500, then start_verification, then poll get_list. If start returns insufficient_credits, stop. If it returns list_limit, stop and look at the list cap. If the code is one you do not recognize, stop and log the code. Do not map unknown strings onto invalid emails.

Do not share one API key across unbounded workers and hope each stays under the rate column. The key is the workspace. The plan is the workspace. Coordinate one budget. mck_your_key is the only placeholder this page uses. A real key is shown once in portal Settings.

Do not treat webhook retries as the list rate. Webhook tries and the fixed gap are about delivering an event to your URL. They are not the 30-per-minute column. Do not sleep an expanding backoff in a verification loop and comment it as the published rate policy. Pace using the published per-minute number as a ceiling you choose to respect, and stop on the named credit and list errors.

When the run fits the credits, the row cap, and the list cap, start it once and let it finish. Plan numbers move only when that page moves.

When a response carries an error code you have not listed, store the code string and stop that worker. A table of ten guessed synonyms for rate limit will eventually map a credit error onto a sleep, and the sleep will retry a start that cannot succeed until someone pays. Sleep is appropriate only for a condition you have named as transient, such as list_busy while you poll get_list. insufficient_credits is not transient until the balance changes. Polling it every second spends nothing useful and hides the zero from the operator.

When a ticket quotes a different cap, re-read the pricing page before you code a status the table does not define.

RELATED ARTICLES

More from the journal.

A chute with one exit is the large shape, with a thin slip pulled out on its own apart from it.Catch-All & Disposable
19 min read

Catch-all email results: what to keep, review, or suppress

When a list comes back catch-all, deleting the segment and marking it valid are both the wrong default. Acceptance proves domain policy. Your records decide keep, review, or suppress.

Read article
A building with no mail slot is the large shape, with a building with one mail slot apart from it.Protocols & Syntax
19 min read

What an MX lookup can prove when a website already loads

A loading website proves that a web server answered. An MX lookup proves only the mail-exchange data DNS returned. This guide separates those facts from the assumptions people attach to them, including implicit MX, null MX, and an unreachable server.

Read article
A building with one mail slot is the large shape, with a short stack of blank cards apart from it.Protocols & Syntax
19 min read

What an SMTP accept response proves about an email address

SMTP verification answers whether a mailbox server accepted a recipient during a check. This guide shows how to read that reply, and how to map accept, reject, defer, and timeout onto categories you can operate.

Read article
A short stack of blank cards is the large shape, with an open door with a blank interior apart from it.MCP & AI Agents
19 min read

Email verification MCP: run a list without blocking the agent

An operator's sequence for the MailCheckup MCP server: read credits, load one list in chunks of 500, poll without blocking, leave unknown in place, and wait for the export email.

Read article
A reply slip already moving away is the large shape, with a solid token with no digits apart from it.Webhooks & APIs
19 min read

Email verification webhooks: ack fast, apply once

A receiver design for developers who take MailCheckup list events on their own HTTPS URL: signature on the raw body, a stored evt_ id, an 8-second ack, and an action for all 10 published events.

Read article
A key kept off the papers is the large shape, with a card coming back along an arc while the stack stays put apart from it.Webhooks & APIs
18 min read

Email verification API workflow for list jobs

A developer can put list verification into an application through the MailCheckup MCP server and webhooks. This is the run order, the failure states that are not an invalid address, and the credit-hold rules. It does not invent a REST base URL or a JSON schema.

Read article
A blank clipboard is the large shape, with a clock with no numerals apart from it.Deliverability & Hygiene
19 min read

Real-time email verification: should the signup form wait?

Wait on a signup email check only for broken syntax or a finished permanent reject inside a budget you set. A timeout or unknown result stays unresolved, and a confirmation link still has to prove the person controls the inbox.

Read article
A short stack of blank cards is the large shape, with a shallow empty tray apart from it.Bulk Lists & Files
19 min read

Bulk email list verification before a send or CRM import

A file of addresses is not a send list and not a CRM update until each stored address has a branch: syntax, disposable, role, no usable mail server, catch-all, deliverable, or unknown.

Read article