API and MCP
Connect an assistant or a bot to My PA Buddy. Everything goes through the member's PA, so it files things the same way the app does, keeps an undo for every change and shows it in the member's PA chat. Version 1.
Two kinds of key
- Member key (
mpb_…): a member makes it in their planner under Account → Assistant and API keys. It acts for that member only. Use it for their own Claude, ChatGPT, Grok or script. - Brand master key (
mpbm_…): a brand admin makes it under Admin portal → Master keys. It acts for any member of that brand, never another brand's. Use it for PA Master or a company bot that handles messages for many members. Every call is audited, and the member sees “via PA Master” in their chat.
Send a key as Authorization: Bearer <key>, as X-API-Key: <key>, or (MCP only, for connector screens that take just an address) as ?key=<key>. Treat an address containing a key like a password. A member key is refused on the master endpoints and a master key on the member ones.
MCP
- Member:
https://mypabuddy.itbotsolution.com/api/mcp - Brand master:
https://mypabuddy.itbotsolution.com/api/mcp/master
Streamable HTTP. The tools have the same names in both, so a bot that knows the member server knows the master one; on the master server every tool also says who it is for, and takes source. There is no master. prefix.
- pa_message: Anything said in natural language: text, photoNotes, urls (https links to photos, PDFs, voice notes), images (data URLs), files (base64), sentAt, replyToBatch. Files meals, exercise, weight, water, sleep, notes, documents, tasks and meetings; changes or removes what it refers to; answers questions; asks when unsure. Returns what it filed with undo references.
- drop_in_inbox: Keep text and files to sort later, without filing.
- list_inbox: What is waiting for an answer, with the PA's question.
- get_today: One day: meetings, tasks, meals, exercise, weight, water, sleep, notes, day rules.
- get_range: Every record between two dates, with ids.
- update_item / delete_item: Change or remove one record by collection (health, daily, tasks, meetings, contacts, companies), docId and itemId.
- undo: Put back the last change, or a specific one from an undo reference.
- upload_media: Keep a photo, PDF or voice note in the member's store and get its fileId: url (https, best) or base64.
- attach_media: Put those files on a record: a comment on a task or meeting, or a meal, journal note or kept document.
- get_file: A photo or file by id (images inline, others as a 24-hour link).
- add_contact / find_contact: The member's own contact book: keep a person or a company (a company named on a person is made too), and look somebody up by name, email or number. add_task and add_meeting take contacts: [names or ids], and tag a person's company with them.
- list_checks / check_page: The member's page checks — is this a scam, is it an advert, is it worth reading, what needs checking. They answer with calibrated probabilities and never a verdict, and each costs the member credits from their daily allowance.
- export: Meals, exercise, notes, tasks, meetings or contacts as CSV or JSON.
- search: Find anything written, however long ago: tasks, comments, meetings, journal entries, day notes, documents, meals, exercise, and people and companies. Narrow with from / to / type (all, tasks, meetings, journal, health, comments, contacts). Every hit carries its own date, so it answers "when did I…".
- log_meal, log_exercise, log_weight, log_water, log_sleep, add_note, add_task, add_meeting: Typed shortcuts with structured fields; they go through the same PA executor (duplicate check, undo, chat line).
- resolve_member (master only):
{ phone?, phoneCc?, email?, externalIds? }→{ memberId, name, status, modulesEnabled, by, linked }. Optional — the other tools take the same details directly — but useful to get the member's name and id, or to link a contact id.
You don't need the member id
Reception usually has only the number the message came from, so every master tool accepts whichever identifier you hold: memberId, phone (E.164 +447700900123, or national with phoneCc), email, or externalIds { botinboxContactId, hubContactId }. The number matches the member's profile mobile or a linked channel (WhatsApp, Telegram). Give more than one and they must point at the same member, or you get ambiguous.
Pass a contact id from BotInBox or the hub alongside a phone or email once, and it is remembered against that member — afterwards that id alone identifies them, and linked in the reply tells you it was saved. A linked id belongs to that brand and that member: if their mobile later changes, the id still finds them (it is matched separately from the number), and the new number starts matching as soon as they save it under Account.
# first time: link the contact id to the member the number proves
curl "https://mypabuddy.itbotsolution.com/api/v1/master/resolve?phone=%2B447700900123&botinboxContactId=c_8812" \
-H "Authorization: Bearer mpbm_…"
→ { "memberId": "cm…", "name": "Sam", "state": "active_linked", "by": "phone", "linked": ["botinbox"] }
# afterwards the id alone is enough, here and on every tool
curl "https://mypabuddy.itbotsolution.com/api/v1/master/resolve?botinboxContactId=c_8812" -H "Authorization: Bearer mpbm_…"
curl -X POST https://mypabuddy.itbotsolution.com/api/v1/pa -H "Authorization: Bearer mpbm_…" \
-H "X-On-Behalf-Botinbox: c_8812" -H "Content-Type: application/json" -d '{"text":"chase the plumber"}'source (master): { channel: "whatsapp" | "email" | "manual" | "other", from, externalMessageId, rawText }. It goes into the audit trail. A repeated externalMessageId returns the first answer and files nothing again, so retries are safe.
pa_message { "phone": "+447700900123", "text": "dentist Thu 15:00",
"urls": ["https://…/photo.jpg"],
"source": { "channel": "whatsapp", "from": "+447700900123", "externalMessageId": "wamid.123" } }
→ "Added the meeting: Dentist, Thu 24 Sep 15:00" (+ actions with undo references)
resolve_member { "phone": "+447700900123", "externalIds": { "botinboxContactId": "c_8812" } }
→ { "memberId": "cm…", "name": "Sam", "status": "active", "by": "phone", "linked": ["botinbox"] }
upload_media { "phone": "+447700900123", "url": "https://…/boiler.jpg" } → { "fileId": "m2x…" }
attach_media { "phone": "+447700900123", "fileIds": ["m2x…"],
"collection": "tasks", "docId": "t_91", "caption": "Boiler serial plate" }
→ "Added 1 file to task \"Book boiler service\"." (as a comment on the task)The Reception pattern
A bot handling messages for many members does the same three things every time.
- Say who it is for with the mobile the message arrived on — no lookup step needed. Use
resolve_memberonly when you want their name, or to link a contact id. - Pass their words on with
pa_message(RESTPOST /pa) and asourcenaming the channel. A message relayed fromwhatsapp,emailormanualis treated as a relay: the PA files what they asked for rather than replying as if it were chatting to them, and a request for something to happen (“book the boiler service for Thursday morning”) becomes a task. SendintentHint: "record"to ask for that explicitly from any channel. A question is still answered, not filed. - Use the typed tools when you already know the shape:
add_task,add_meeting,log_mealand friends skip the model entirely, so they are faster and exact.
Always send the channel's own message id. A retry with the same id returns the first answer and writes nothing again — on both MCP (source.externalMessageId) and REST (X-Source-Message-Id), where the reply carries repeat: true. Separately, the PA notices the same thing said twice within a couple of hours and says it is already on the list instead of filing it again.
REST (v1)
JSON in and out, base https://mypabuddy.itbotsolution.com/api/v1. With a master key, add X-On-Behalf-Of to every call — the member's id, mobile or email, whichever you have (a national number needs X-On-Behalf-Phone-Cc; a linked contact id goes in X-On-Behalf-Botinbox or X-On-Behalf-Hub). Optionally add X-Source-Channel, X-Source-From, X-Source-Message-Id for the audit trail.
- GET /master/resolve?phone=&phoneCc=&email=&botinboxContactId=&hubContactId= (master key): find a member of the key's brand, and link a contact id. 404
not_found, 409ambiguous. - POST /pa: one PA turn.
{ text, urls?, images?, files?, sentAt?, replyToBatch? }, or multipart withtextand repeatedfile/url. Returnsreply,actions(with undo),asks,attachments,retry(true = nothing was saved, send again). - POST /inbox, GET /inbox: keep things to sort later; list what is waiting.
- GET /day?date=YYYY-MM-DD, GET /range?from=&to=: records with ids.
- PATCH /items, DELETE /items: change or remove one record —
{ collection, docId, itemId? }from/range. A removed record leavessearchand/rangeat once; the reply'sundoreference puts it back within 7 days through POST /undo. - GET /search?q=&from=&to=&type=&limit=: one record per hit (a comment, a meal, a journal line) with its own date, title and snippet, newest first.
- GET /contacts?q=&kind=&limit=, POST /contacts: the member's contact book — people and the companies they belong to. POST takes
{ name, kind, company?, role?, email?, phone?, phoneCc?, whatsapp?, wechat?, country?, address?, notes? }. A number is kept as country code + national + E.164, so07700 900123and+44 7700 900123are the same number. Somebody of that name already kept comes back withalreadyinstead of a second copy. Tag work to them withcontactson the MCPadd_task/add_meeting, or in the planner under “Who it’s for”. - POST /files: keep a file — multipart
file(up to 10), or JSON{ url }/{ base64, type, name }. Returnsfiles: [{ fileId, type, kind, size, takenAt }]. - POST /files/attach:
{ fileIds, collection, docId, itemId?, caption? }— onto a task or meeting (as a comment whenitemIdis left out), a meal, a journal note or a kept document. - POST /undo, GET /files/<id>, GET /export?what=&from=&to=&format=csv (
what: meals, exercise, notes, tasks, meetings, contacts).
curl https://mypabuddy.itbotsolution.com/api/v1/master/resolve?phone=%2B447700900123 -H "Authorization: Bearer mpbm_…"
# no member id needed: the mobile the message came from is enough
curl -X POST https://mypabuddy.itbotsolution.com/api/v1/pa -H "Authorization: Bearer mpbm_…" -H "X-On-Behalf-Of: +447700900123" \
-H "X-Source-Channel: whatsapp" -H "X-Source-Message-Id: wamid.123" \
-H "Content-Type: application/json" -d '{"text":"lunch","urls":["https://…/photo.jpg"]}'
curl -X POST https://mypabuddy.itbotsolution.com/api/v1/files -H "Authorization: Bearer mpbm_…" -H "X-On-Behalf-Of: +447700900123" \
-H "Content-Type: application/json" -d '{"url":"https://…/boiler.jpg"}'
→ { "files": [ { "fileId": "m2x…", "type": "image/jpeg", "size": 184320 } ] }
# remove something, and put it back
curl -X DELETE https://mypabuddy.itbotsolution.com/api/v1/items -H "Authorization: Bearer mpbm_…" -H "X-On-Behalf-Of: +447700900123" \
-H "Content-Type: application/json" -d '{"collection":"tasks","docId":"t_91"}'
→ { "ok": true, "changed": [ { "label": "Removed task \"Book boiler service\"",
"undo": { "day": "2026-09-23", "msgId": "…", "idx": 0 } } ] }
curl -X POST https://mypabuddy.itbotsolution.com/api/v1/undo -H "Authorization: Bearer mpbm_…" -H "X-On-Behalf-Of: +447700900123" \
-H "Content-Type: application/json" -d '{"day":"2026-09-23","msgId":"…","idx":0}'Machine-readable: /api/v1/openapi.json.
Files
Give a link wherever you can: the real file is kept, and the limit is highest. Base64 inside a JSON argument is a third bigger again and breaks most MCP transports, so it is capped lower on purpose.
- 20 MB — an https
url(MCPupload_media, RESTPOST /files,urlsonpa_message), and a multipartfile. - 5 MB —
base64in a tool argument or JSON body (upload_media,filesonpa_message,POST /files). - 12 MB, up to 6 files in an hour — the upload link the PA hands a member for photos it cannot receive itself.
- Types: image/jpeg, image/png, image/webp, image/gif, application/pdf, video/mp4, video/webm, audio/webm, audio/mp4, audio/mpeg, text/plain, text/csv, text/markdown, application/json, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/vnd.oasis.opendocument.text, application/vnd.oasis.opendocument.spreadsheet, application/rtf. Web pages are refused, and so are links to private or internal addresses. Up to 5
urlsper call. - Photos are kept at up to 1280 px, with the date they were taken. Files stay in the member's own account and count against their storage.
- Screen captures are different: send
sharp=1(multipart) or"sharp": true(JSON) onPOST /files,POST /paorPOST /inboxand the image is kept at up to 2048 px, with a PNG left as a PNG, so the text in it can still be read. It uses more of the member's storage, so it is never assumed.
Checks
POST /api/v1/check runs one of the member's checks over some text and answers with probabilities — never a verdict, never prose. GET lists what they have and how many credits are left; PATCH switches one on or off for them.
curl -X POST https://mypabuddy.itbotsolution.com/api/v1/check -H "Authorization: Bearer mpb_…" -H "Content-Type: application/json" -d '{"tool":"scam-check","title":"Invoice overdue","url":"https://…","text":"…the email…"}'Three kinds of answer come back, keyed by the ids the check defines: a noul is a bare probability ({ type: "noul", noul: 0.95 }), a choice names one option with a probability for each and its own confidence, and a score gives a position on a named scale. A check with claims in the reply read the page for candidate sentences first, which is why it costs more.
- Checks are defined in the portal (Set-up → Checks), and a brand can keep its own wording and prices.
- Credits are a separate daily allowance from AI calls, because a check costs a tiny fraction of one. A plan or brand set to 0 has no checks.
- Nothing is charged unless a check answered: a refusal, a timeout or an unreadable answer is free (
503 unavailable). - The text sent is not stored. The reply carries probabilities, not the page.
Saying where a call came from, and sending it twice
Three headers travel with a call, on a member key as well as a master one:
X-Source-Message-Id— the channel's own id for the message. The first answer is kept against it, and a repeat returns that same answer withrepeat: trueinstead of filing again. This is what makes a retry after a dropped connection safe; the browser extension sends one with every capture.X-Source-Channel— where it came from, in a word.extensionis shown to the member as “the browser extension”; a relay channel (whatsapp,email,sms,telegram,manual) also tells the PA it is carrying someone's message in rather than talking to them. It is provenance, not permission: anyone could claim it, and nothing is trusted because of it.X-Intent-Hint: record— file what this says, do not chat back.
Both POST /pa and POST /inbox also take contacts (ids from find_contact, or names): whoever it names is put on everything that call files, with their company alongside them.
Errors
Every error is { error: { code, message } } (MCP: a tool result with isError and the same object).
invalid_token(401) — revoked, expired, mistyped, or not allowed from this address.not_found(404) — no member of this brand matches, or that record is gone.ambiguous(409) — the details given belong to different members.forbidden(403) — the member isn't in this key's brand, or the brand is suspended.flag_off(403) — assistant access is switched off for the brand.- Identity errors also carry a
reason, and ahintyou can say to the person:no_member(nobody here matches — if they say they have joined, they may not have saved their mobile, so ask for their email),no_mobile_match(a member matches, but that mobile isn't on their account — ask them to add it under Account),not_in_brand,suspended. Another brand's member is never distinguishable from a stranger. invalid_argument(400),too_large(413),unsupported_type(415),quota_or_state(507: their storage is full),conflict(409: the record changed while saving — send it again).rate_limited(429) — 120 calls a minute for a member key, 600 for a master key.
Not in v1
- Outbound webhooks: every call answers straight away with what was filed.
- Reminders as their own record: use a task with a due date, or a meeting.
- Speech-to-text for voice notes.
Members can read the friendlier guide in Connect your PA, and the browser extension is this API with a button on it.