Skip to content

Tool Reference

The complete tool surface of mcp.elasticpay.co. The five documentation and schema tools need no authentication and are also served alone at https://mcp.elasticpay.co/mcp/docs; everything else requires a connection and operates on your sandbox account.

The live read-only server at /mcp/live is a separate, smaller surface: the docs tools plus the same read tools as sandbox — whoami, list_customers, get_customer, list_customer_payment_intents, list_payment_methods, get_payment_intent, list_payment_plans, get_payment_plan, list_plan_payment_intents, and list_webhook_events — with identical parameters, live data, and no write tools at all. Anything an agent reads on a live account it can rehearse on sandbox first. See Operate a live account.

Each tool wraps one call to the REST API, so responses are the API’s JSON verbatim — statuses, references (cus_…, pm_…, pi_…), and error shapes match the API documentation exactly. The exceptions are the customer-import and payment-plan-import tools, whose responses and error envelope follow their own shared contract, described below.

Tool What it does
search_docs Search this documentation; returns the most relevant pages with snippets and Markdown URLs
get_doc_page Fetch one documentation page as Markdown by path, e.g. api/getting-started/quick-start
get_openapi_schema Return the full OpenAPI 3.1 schema — the authoritative request/response shapes
list_endpoints List every API endpoint as method, path, and summary
describe_endpoint Return the full OpenAPI operation (parameters, request body, responses) for one endpoint
Tool Parameters What it does
whoami — Describe the current connection: auth kind (oauth or api_key), mode, and for OAuth the connected sandbox account
Tool Parameters What it does
create_customer name, email, billing_email?, reference?, test_clock? Create a sandbox customer. billing_email is where billing correspondence goes when it differs from email, and the list_customers email filter matches it too. Pass a test_clock (clk_…) at creation for plans that should follow simulated time
list_customers limit?, starting_after?, email?, name?, reference?, status?, test_clock? List customers, newest first, with cursor pagination. name is a partial, case-insensitive match; email is an exact, case-insensitive match on email or billing_email; status is active, hold (created with a payment method still to be collected) or cancelled; it’s informational and doesn’t start or stop payments. reference is an exact, case-insensitive match on your candidate key, so it returns at most one customer. Customers created on a test clock appear only when test_clock names their clock; test_clock is sandbox only
get_customer customer_id Fetch one customer in full: contact details, billing and shipping addresses, phones, notification and surcharge preferences, and additional_attributes
list_customer_payment_intents customer_id, limit? List a customer’s payment intents, newest first
Tool Parameters What it does
create_payment_method fixture_token, customer_id?, card_name? Save a card or bank account using a sandbox fixture token — no widget, real card or real account involved. A card fixture’s outcome (succeed, decline, 3DS, timeout) travels with the saved method. tok_sandbox_au_becs_debit saves a bank account with an accepted mandate, whose debits settle on the test clock; the failing bank fixtures fail every debit
list_payment_methods customer_id? List saved payment methods, optionally for one customer
detach_payment_method payment_method_id Detach a payment method so it can no longer be charged
Tool Parameters What it does
create_payment_intent amount, currency?, customer_id?, payment_method?, metadata? Create a payment intent. Amounts are integer cents (minimum 200), currency AUD
confirm_payment_intent payment_intent_id, payment_method? Confirm the intent, executing the charge. Pass payment_method — confirmation requires it even when one was given at creation. total_amount in the response is what was charged, and includes any surcharge added here
get_payment_intent payment_intent_id Fetch an intent and its current status
cancel_payment_intent payment_intent_id Cancel an intent that has not completed. A plan’s payment is skipped, as the dashboard’s Skip does, and the plan collects the amount at the end if it has a total. That’s refused with invalid_status_for_cancel, changing nothing, when the payment is dated today or earlier, falls inside a suspension period, belongs to a closing or closed plan, or has been claimed or sent for processing: see Canceling a plan’s payment
refund_payment_intent payment_intent_id, amount?, reason? Refund a succeeded intent. What is refundable is total_amount, not the amount the intent was created for — omit amount for a full refund
Tool Parameters What it does
create_payment_plan customer_id, recurring_amount_cents, start_date, frequency_type?, number_of_payments?, until_further_notice?, payment_instrument_id?, name?, failure_behaviour? Create a recurring plan. Frequencies: weekly, fortnightly, monthly, quarterly, annual. failure_behaviour is NEW_AT_END (default), TRY_AGAIN, DOUBLE_UP or DO_NOTHING — see failure behaviours
activate_payment_plan payment_plan_id Activate the plan so scheduled payments start
suspend_payment_plan payment_plan_id Suspend an active payment plan until you resume it. Payments due meanwhile are skipped; a plan with a total runs longer. Not the same as add_plan_suspension_period, which has end dates. Safe to repeat
resume_payment_plan payment_plan_id Resume a suspended payment plan, whatever suspended it, from today. Refused while the plan has no usable payment method. Safe to repeat
list_payment_plans limit?, starting_after? List the account’s recurring payment plans
get_payment_plan payment_plan_id Fetch a plan, its current status and its schedule changes (payment_adjustments, balance_adjustments, suspension_periods). state is draft, active, inactive, suspended, closing or closed. remaining_amount_cents is what it has left to schedule beyond what was collected or is in flight; 0 with no next_date means nothing more will be scheduled, not that its last payments were sent or settled (list_plan_payment_intents shows their status). A payment that fails later is collected again unless the plan is closed. pause says why a suspended plan isn’t collecting
list_plan_payment_intents payment_plan_id, limit? List the intents a plan has generated — how you observe a renewal after advancing a clock
adjust_plan_payment payment_plan_id, date, amount_cents, type, change_total_amount?, idempotency_key Set what one future date collects; 0 skips it. type is required: aligned (recommended) when the plan should now expect the new amount, manual when it should still expect the scheduled amount, so a shortfall shows as arrears
remove_plan_payment_adjustment payment_plan_id, date, idempotency_key Undo the change to a date; the total never changes
add_plan_balance_adjustment payment_plan_id, date, amount_cents, description?, external_reference?, idempotency_key Record money collected outside the plan’s debits (a non-debit payment in the dashboard). external_reference is your own free-form reference, not checked for uniqueness; a blank one is treated as absent
remove_plan_balance_adjustment payment_plan_id, balance_adjustment_id, idempotency_key Remove a balance adjustment; the plan collects the amount again
add_plan_suspension_period payment_plan_id, start_date, end_date, idempotency_key No payments between two dates, both included. Not suspend_payment_plan, which has no end date
change_plan_suspension_period payment_plan_id, suspension_period_id, start_date, end_date, idempotency_key Move a suspension period
remove_plan_suspension_period payment_plan_id, suspension_period_id, idempotency_key Remove a suspension period that hasn’t begun
close_payment_plan payment_plan_id, closing_amount_cents, accept_large_closing_amount?, idempotency_key Close a plan for good, optionally collecting a final amount first, scheduled in instalments of up to $300. The plan is closing until its final payments have succeeded (a card payment when it’s approved, a bank debit once it clears), then closed. A final amount above 0 that equals or exceeds the remaining balance needs accept_large_closing_amount: true; after a refusal for want of it, call again with it and a new idempotency_key. See Close a plan

The schedule tools and close_payment_plan are sandbox only, like every write tool. Each needs an idempotency_key: a new unique value for each change, and the same value to retry it, which returns the original result without applying the change twice. Reusing a key for a different request is refused. The rules are the API’s: see Changing a plan’s schedule. suspend_payment_plan and resume_payment_plan take no idempotency_key: they’re safe to repeat.

Tool Parameters What it does
create_setup_intent customer_id?, metadata? Create a setup intent for saving a payment method without charging
confirm_setup_intent setup_intent_id, payment_method_id Confirm a setup intent with a saved payment method

Sandbox time under programmatic control — the full concept is covered in Test clocks. Up to 3 clocks can be active at once.

Tool Parameters What it does
create_test_clock frozen_time, name? Create a clock frozen at an ISO 8601 time. Attach customers at creation via create_customer
simulate_bank_dishonour payment_intent_id, code Dishonour one sandbox bank debit that has been sent and not yet settled, at the test clock’s time. See bank debit outcomes for the codes
simulate_bank_late_return payment_intent_id, code Return one settled sandbox bank debit late, at the test clock’s time. late_return and late_return_insufficient_funds are collected again under the plan’s failure behaviour; dd_claim and recall stop the bank account and suspend every plan of the customer for your review, with no email to the customer
advance_test_clock test_clock_id, frozen_time Advance to a future time. Asynchronous: status goes advancing then ready — poll get_test_clock, then inspect plans, intents, and events for what fired
get_test_clock test_clock_id Fetch a clock and its status
list_test_clocks — List test clocks
delete_test_clock test_clock_id Delete a clock and its simulated resources
Tool Parameters What it does
list_webhook_events event_type?, limit?, starting_after? List the account’s recent webhook events, newest first, each with its latest delivery status. Webhooks are the source of truth for payment outcomes — this is how an agent closes the loop without hosting an endpoint

Five tools that stage a bulk customer dataset, freeze it into a content-hashed manifest, and hand that manifest to the merchant for approval in their dashboard. Approval is never an API call, and neither are the merchant’s stop and rollback controls — the agent that proposed an import can never operate the controls that govern it. The walkthrough is Migrate customers with an agent.

These tools exist on the sandbox server only, and only for OAuth connections: the merchant’s approval binds to the connected application, which a raw sk_sandbox_ key does not identify. A call over an API-key connection is refused with that explanation. Live enablement is gated on a separate release; today the API answers sandbox_only for a non-sandbox account.

Every import is bound at begin_customer_import to your sandbox account and the connected application. The tool inputs carry no account or connection identity — the server derives both from the token, and an import belonging to another account or another application answers not_found.

Tool Parameters What it does
begin_customer_import import_key, source_reference, declared_count, field_mapping, requested_decide_by? Create a staging import with an exact row budget. Returns the cim_… reference, the limits in force, and staging_expires_at. Idempotent on import_key
append_customer_import_rows customer_import, chunk_key, rows Stage one chunk of 1–500 rows. Atomic: accepted whole or rejected whole. Returns accepted and the running staged_total. Idempotent on chunk_key
finalize_customer_import customer_import Freeze the rows, validate the complete dataset, and propose it to the merchant. Returns the action (aoa_…), dataset_hash, row_count, the projection the merchant will see, and decide_by
get_customer_import customer_import Poll the combined state. The body is state-shaped: progress while executing, outcome once execution has ended, rollback_action once rolled back
cancel_customer_import customer_import Withdraw an import that is staging or requires_approval. An approval, once given, belongs to the merchant and cannot be cancelled from here

begin_customer_import:

Field Type Notes
import_key string, 1–128 Idempotency key, scoped to your connection and account
source_reference string, 1–200 Human label for where the rows came from; shown to the merchant
declared_count integer, 1–10,000 The exact number of rows you will stage — a budget, not a ceiling
field_mapping object, ≥1 key Display provenance: allow-listed target field → the source column it came from. It neither transforms rows nor gates validation; rows must already be in target shape
requested_decide_by ISO 8601 date-time, optional Ask for a decision deadline; capped at 7 days from finalisation

append_customer_import_rows:

Field Type Notes
customer_import cim_… From begin_customer_import
chunk_key string, 1–128 Idempotency key, scoped to the import
rows array, 1–500 Rows in the shape below. Every source_row_key must be unique across the whole import

The other three tools take only customer_import.

Rows are validated for shape at append_customer_import_rows; unknown fields are rejected, so this list is the whole surface.

Field Required Type
source_row_key yes string, 1–120 — your stable id for the row, used in every error and failure report
name yes string, 1–200
email yes email, ≤254
reference no string, 1–60 — the merchant’s own customer id, a candidate key: unique per account (trimmed, case-insensitive). Set it; the payment-plan import names customers by it
business_name no string, 1–200
billing_email no email, ≤254
currency no 3-letter uppercase code
timezone no string, 1–64
sms_phone_raw no string, 1–32
sms_phone_country no 2-letter uppercase country code
billing_address no address object
shipping_address no address object

An address object accepts line1, line2 (≤200 each), city_or_suburb, state_or_region (≤100 each), postal_code (≤20), and country (2-letter uppercase code), all optional, nothing else.

Excluded by construction: consent_authorised, payment_amount_limit_exempt, fee_preferences, notification_preferences, status, and test_clock cannot be imported. An import asserts no consent and grants no exemptions on anyone’s behalf. additional_attributes is reserved for a later release and rejected today.

get_customer_import returns one status field carrying the combined judgment and workflow state:

staging ──finalize──▶ requires_approval ──approve──▶ approved ─▶ executing
│ │ │ │
│ cancel / staleness │cancel │ decide_by passes merchant │
▼ ▼ ▼ stop │ │
cancelled cancelled expired ▼ ▼
rejected ◀─ merchant rejects stopped completed |
│ partially_completed |
│ failed
└──────┬──────┘
merchant rollback▼
rolled_back
Status Meaning
staging Rows are being appended. No manifest exists yet
requires_approval Frozen and proposed; waiting for the merchant
approved The merchant said yes. Transient — execution starts automatically
executing Rows are being created; progress carries created, failed, remaining
completed / partially_completed / failed Execution ended; outcome carries created, failed, and up to 20 failures_sample entries keyed by source_row_key
stopped The merchant halted execution. Rows never claimed did not run; customers already created remain. Distinct from partially_completed so “some rows failed” and “I stopped it” stay separate facts
rejected The merchant said no
expired Nobody decided before decide_by. Silence never approves
cancelled Withdrawn by the agent, by staging staleness, or by revocation of the connection while unapproved
rolled_back The merchant ran the compensating rollback; rollback_action names it. Only import-created customers with no later records and no merchant edits are archived; every skip is reported to the merchant

The poll body is state-shaped: staging has no action, dataset_hash, or decide_by; executing carries progress and a null outcome; the four terminal-executed states carry outcome and a null progress; rolled_back additionally carries rollback_action. While executing, created + failed + remaining equals the row count; at stopped, created + failed can fall short of it by exactly the rows that never ran.

Revoking the connection while an import is staging or requires_approval cancels it. Revoking after approval does not halt execution — the merchant’s approval is the authority, and the merchant holds the stop control — the agent merely loses the ability to poll.

Every keyed call stores a fingerprint of the agent-supplied payload. Server-derived identity is excluded from the fingerprint, so a routine token refresh never breaks a replay.

  • begin_customer_import is idempotent on import_key per connection and account; append_customer_import_rows on chunk_key per import. The same key with a byte-identical payload replays the original response with replayed: true. The same key with a different payload answers idempotency_conflict — corrected rows need a new chunk_key, never a reused one.
  • A chunk is atomic, so a replayed chunk_key never means half a chunk.
  • finalize_customer_import replays its original response only while the import is still requires_approval; in any later state it answers state_conflict — poll get_customer_import instead.
  • cancel_customer_import replays while the import is cancelled.
  • After finalisation, every mutation answers post_finalisation_mutation. Any change to the dataset is a new import.
  • append_customer_import_rows rejects unknown row fields, duplicate source_row_keys (duplicate_source_row_keys, with the offending keys in details), and any chunk that would take the staged total past declared_count (limit_exceeded).
  • finalize_customer_import requires staged rows to equal declared_count exactly (declared_count_mismatch) and refuses a dataset with zero valid rows (zero_valid_rows). Rows that pass shape checks but fail model validation — an email the API rejects, a reference already taken — stay in the frozen dataset, are counted as invalid in the projection with up to 20 errors_sample entries, and become per-row failures at execution.
  • A row valid at finalisation can still fail at execution if, say, its reference is taken in between; it appears in outcome.failures_sample.
Limit Value
declared_count 1 – 10,000
Rows per chunk 1 – 500
decide_by 72 hours from finalisation by default; requested_decide_by capped at 7 days
Staging TTL A staging import untouched for 7 days is cancelled and its rows purged
Staged-row retention Rows of a terminal import are purged 30 days after the terminal state; the manifest (hash, counts, projection) is permanent

Import errors return as a tool error whose text is code: message, followed by any details and meta as JSON — the whole envelope, because the details (duplicate keys, staged-versus-declared counts) are what an agent needs to correct its request.

Code When
not_found Unknown import, or one belonging to another account or another connected application
inactive_biller The account is not active
state_conflict The call is not allowed in the import’s current state — e.g. cancelling after approval, or finalising again after the merchant has decided
idempotency_conflict A reused import_key or chunk_key whose payload differs from the original
post_finalisation_mutation An append or other mutation after finalisation
invalid_request The body does not match its request schema, outside the row-specific cases
chunk_too_large More than 500 rows in one chunk
invalid_rows Rows that fail shape validation
duplicate_source_row_keys A source_row_key repeated within the import; details lists them
declared_count_mismatch Finalising with staged rows ≠ declared_count
zero_valid_rows Finalising a dataset in which no row would create its record (a customer, a payment plan)
limit_exceeded A chunk that would exceed declared_count, or any other limit

Payment plan imports (sandbox, OAuth only)

Section titled “Payment plan imports (sandbox, OAuth only)”

Five tools that stage a bulk dataset of recurring schedules for customers who already exist on the account, freeze it into a content-hashed manifest, and hand it to the merchant for approval in their dashboard. The envelope is the customer import’s — the same calls, states, poll shape, idempotency rules, limits, and error codes — applied to plans, so this section states only what differs and points to the customer-import section for the rest. The walkthrough is Migrate payment plans with an agent.

The same gate applies: sandbox server only, OAuth connections only (connected_app_required over an API key, sandbox_only for a non-sandbox account), identity derived from the token, and not_found for an import belonging to another account or application. References are pim_….

Every plan an import creates is a draft. It has no payment instrument, generates no payment intents, and moves no money. It activates when the customer adds a payment method or when the merchant activates it in the dashboard — never by the import.

Tool Parameters What it does
begin_payment_plan_import import_key, source_reference, declared_count, field_mapping, requested_decide_by? Create a staging import with an exact row budget. Returns the pim_… reference, the limits in force, and staging_expires_at. Idempotent on import_key. Nothing binds it to a customer import: customers are resolved by reference at finalisation
append_payment_plan_import_rows payment_plan_import, chunk_key, rows Stage one chunk of 1–500 plan rows. Atomic, idempotent on chunk_key; every source_row_key must be unique across the import. Rows are validated for shape here — including the two exactly-one rules below
finalize_payment_plan_import payment_plan_import Freeze the rows, resolve each row’s customer, check start dates, and propose the dataset to the merchant. Returns the action, dataset_hash, row_count, projection, and decide_by
get_payment_plan_import payment_plan_import Poll the combined state — the same state-shaped body as get_customer_import
cancel_payment_plan_import payment_plan_import Withdraw an import that is staging or requires_approval

begin_payment_plan_import takes the same fields as begin_customer_import with the same types and meanings; field_mapping keys are the plan row fields below plus source_row_key. append_payment_plan_import_rows takes payment_plan_import (pim_…), chunk_key, and rows. The other three tools take only payment_plan_import.

Unknown fields are rejected at append_payment_plan_import_rows, so this list is the whole surface.

Field Required Type
source_row_key yes string, 1–120 — your stable id for the row, used in every error and failure report
customer_id one of two cus_… — an existing customer on the account
customer_reference one of two string, 1–60 — the merchant’s own customer id, matched exactly as a candidate key (trimmed, case-insensitive). A customer with a blank reference can only be named by customer_id
name yes string, 1–50
category no string, 1–50
frequency_type yes W (weeks) or M (months)
frequency_period yes integer — 1–52 for W, 1–12 for M (fortnightly W×2, quarterly M×3, annual M×12). A longer cadence cannot be expressed and is rejected here, not approximated
start_date yes ISO 8601 date — the recurring anchor: the first recurring collection and the date later ones are counted from; the next collection when there is no first_date (for a migrated schedule, its next due date). Today or later at finalisation, and not before first_date
first_date no ISO 8601 date — a one-off first collection on or before start_date; when present it, not start_date, is the first collection. Requires first_amount_cents; today or later at finalisation
first_amount_cents with first_date integer, 200–100,000
recurring_amount_cents yes integer, 200–100,000
total_amount_cents one of three integer, 200–99,999,999 ($999,999.99) — end when this total has been collected
number_of_payments one of three integer, ≥1 — end after this many recurring payments. A first payment (first_date + first_amount_cents) is in addition, so the total is number_of_payments × recurring_amount_cents + first_amount_cents. A total over $999,999.99 makes the row invalid at finalisation
until_further_notice one of three the literal true — no end condition
failure_behaviour no NEW_AT_END (default), TRY_AGAIN, DOUBLE_UP, or DO_NOTHING — see failure behaviours

Two rules are enforced on every row at append: exactly one of customer_id / customer_reference, and exactly one of total_amount_cents / number_of_payments / until_further_notice. The platform never infers an end condition and never guesses which customer a row means.

Excluded by construction: payment_instrument_id, anything mandate- or consent-shaped, state, payment_plan_template_id, and source cannot be imported. An import asserts no instrument and no consent on anyone’s behalf, which is why every plan it creates is a draft.

finalize_payment_plan_import returns the customer import’s projection — creates, invalid, fields_set, up to 20 errors_sample entries — plus four plan-specific fields:

Field Meaning
creates_as Always "draft". A constant, so the manifest itself records that no plan bills on approval
unresolved_customers Rows whose customer was not found by customer_id or customer_reference — a subset of invalid
lapsed_start_dates Rows whose start_date passed before finalisation — a subset of invalid. The agent re-dates in a new import; the platform never re-dates
customers_referenced Distinct customers the valid rows attach plans to

Customer resolution and the start-date check happen at finalisation, not at append: a row can pass shape validation and still be invalid here. Invalid rows stay in the frozen dataset, are shown to the merchant, and are skipped at execution.

State machine, idempotency, limits, and errors

Section titled “State machine, idempotency, limits, and errors”

Identical to the customer import’s: the same twelve statuses and state-shaped poll body, the same idempotency rules on import_key and chunk_key, the same limits (1–10,000 rows, 500 per chunk, 72-hour default decide_by capped at 7 days, 7-day staging TTL, 30-day row retention), and the same twelve error codes. No plan-specific code exists, because everything that can go wrong with a plan row is a row problem — reported in the projection and per row in outcome, not as a call error.

The one difference is rollback eligibility. The merchant’s rollback closes and archives an import-created plan only while it is still draft, has generated no payment intents, and has not been edited since creation; a plan that has been activated, billed, or edited is skipped and reported. And a customer that now owns an import-created plan has a subsequent record, so a later customer rollback skips that customer too.

There is no tool that accepts card numbers or CVV — card capture goes through the widget or hosted payment page only, exactly as in the REST API. And there are no live-mode write tools anywhere: the sandbox server writes sandbox data only, and the live server is read-only by construction. There is no tool that approves, stops, or rolls back a customer or payment-plan import — those are merchant controls in the dashboard, deliberately absent from the agent API.