This page goes from nothing to an acceptance test plan (ATP). Each step shows both routes:
- Terminal uses
curlandjq. It works anywhere an agent can run shell commands, including Pi. - MCP is what to ask an assistant connected through MCP, with the tool it calls.
Terminal commands build on each other, so run them in one shell session or keep the IDs they print.
Create your account
Set the addresses and your details. Use an email address you control. Password sign-in needs at least 8 characters.
export TANDA_APP=https://www.testandaccept.com export TANDA_API=https://api.testandaccept.com/api/rest export TANDA_JAR="$(mktemp)" export TANDA_NAME="Ada Lovelace" export TANDA_EMAIL="ada@example.com" export TANDA_PASSWORD="$(openssl rand -base64 24)"Save the generated password in your password manager, then sign up. The session is kept in the cookie file:
curl -sS --fail-with-body -b "$TANDA_JAR" -c "$TANDA_JAR" "$TANDA_APP/api/auth/sign-up/email" \ -H "Origin: $TANDA_APP" -H 'Content-Type: application/json' \ -d "$(jq -n --arg name "$TANDA_NAME" --arg email "$TANDA_EMAIL" --arg password "$TANDA_PASSWORD" \ '{name: $name, email: $email, password: $password}')" | jq '.user | {id, email}'Already have an account? Send the same request to
/api/auth/sign-in/email, withoutname. If you sign in with Google, GitHub or Microsoft, skip to the next step and create your token on the Developer page.Sign-up and sign-in allow only a few attempts every few seconds. If you get a
429, wait 10 seconds and try again.Add the server to your client. The first time it connects, your client opens the Tanda sign-in page in your browser. Choose to sign up, or sign in if you already have an account, then approve access.
An account can’t be created over MCP, because connecting needs an account first.
Create an organization
An organization holds your clients and projects, and your team.
Create it, make it your active organization, and set up its file storage:
export TANDA_ORG_NAME="Analytical Engines" export TANDA_ORG_SLUG="analytical-engines-$(openssl rand -hex 3)" export TANDA_ORG_ID="$(curl -sS --fail-with-body -b "$TANDA_JAR" -c "$TANDA_JAR" \ "$TANDA_APP/api/auth/organization/create" \ -H "Origin: $TANDA_APP" -H 'Content-Type: application/json' \ -d "$(jq -n --arg name "$TANDA_ORG_NAME" --arg slug "$TANDA_ORG_SLUG" '{name: $name, slug: $slug}')" \ | jq -r .id)" curl -sS --fail-with-body -o /dev/null -b "$TANDA_JAR" -c "$TANDA_JAR" \ "$TANDA_APP/api/auth/organization/set-active" \ -H "Origin: $TANDA_APP" -H 'Content-Type: application/json' \ -d "$(jq -n --arg id "$TANDA_ORG_ID" '{organizationId: $id}')" curl -sS -o /dev/null -w 'File storage: %{http_code}\n' -b "$TANDA_JAR" "$TANDA_APP/api/organizations/provision" \ -H "Origin: $TANDA_APP" -H 'Content-Type: application/json' \ -d "$(jq -n --arg id "$TANDA_ORG_ID" --arg name "$TANDA_ORG_NAME" \ '{organizationId: $id, organizationName: $name}')" echo "Organization: $TANDA_ORG_ID"The last request sets up file storage and should print
200. If it fails, you can still carry on with the rest of this page.Open testandaccept.com/organization-setup in your browser to create one. Then ask:
Which Tanda organizations can I work in?
The assistant calls
list_organizations. If you belong to more than one, tell it which to use and it callsset_default_organization.Create a token
Create an API token. It’s only shown once, and every request after this uses it:
export TANDA_TOKEN="$(curl -sS --fail-with-body -b "$TANDA_JAR" "$TANDA_APP/api/api-token" \ -H "Origin: $TANDA_APP" -H 'Content-Type: application/json' \ -d '{"name": "agent"}' | jq -r .token)"Save it in your secrets manager. Check that it works:
curl -sS --fail-with-body "$TANDA_API/projects" -H "Authorization: Bearer $TANDA_TOKEN" | jq .totalA new organization has no projects yet, so this prints
0.Nothing to do: your client signed in when it connected.
Create a client and a project
export TANDA_CLIENT_ID="$(curl -sS --fail-with-body "$TANDA_API/clients" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d '{"name": "Globex", "industry": "Manufacturing"}' | jq -r .id)" export TANDA_PROJECT_ID="$(curl -sS --fail-with-body "$TANDA_API/projects" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d "$(jq -n --arg client "$TANDA_CLIENT_ID" '{name: "Customer portal", clientId: $client}')" \ | jq -r .id)" echo "Client: $TANDA_CLIENT_ID Project: $TANDA_PROJECT_ID"Create a client called Globex in manufacturing, and a project for them called Customer portal.
The assistant calls
create_clientand thencreate_project.Invite people
There are two kinds of invitation. A project invitation gives someone access to one project. An organization invitation makes them a member of your organization.
To a project. Access levels are
owner,editor,approver,viewerandfollower. Tanda emails the person. If an account has already verified that address, they’re added straight away and notified:curl -sS --fail-with-body "$TANDA_API/projects/$TANDA_PROJECT_ID/invitations" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d '{"email": "grace@example.com", "accessLevel": "editor", "message": "Please review the plan"}'To the organization. Roles are
adminandmember, and you must be an admin. Tanda does not email this one. Send the person theacceptUrlfrom the response:curl -sS --fail-with-body "$TANDA_API/organization/invitations" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d '{"email": "grace@example.com", "role": "member"}' | jq -r .acceptUrlThe link lasts 7 days and only works for an account with the invited email address.
Invite grace@example.com to Customer portal as an editor.
The assistant calls
invite_project_member, which sends no email. It gives you anacceptUrl, and you send that to the person. The link lasts 7 days and only works for an account with the invited email address.Organization invitations aren’t available over MCP. Use the Terminal route, or invite people from your organization settings in the app.
Write the statement of work
A SOW holds task items. Each item has acceptance criteria, and each criterion has the tests that prove it. Add one of each here, and repeat for the rest of your work.
export TANDA_SOW_ID="$(curl -sS --fail-with-body "$TANDA_API/projects/$TANDA_PROJECT_ID/sows" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d '{"title": "Phase 1", "description": "Customers sign in and see their orders."}' | jq -r .id)" export TANDA_ITEM_ID="$(curl -sS --fail-with-body "$TANDA_API/task-items" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d "$(jq -n --arg sow "$TANDA_SOW_ID" '{sowId: $sow, title: "Sign-in page"}')" | jq -r .id)" export TANDA_CRITERION_ID="$(curl -sS --fail-with-body "$TANDA_API/task-items/$TANDA_ITEM_ID/criteria" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d '{"title": "Customers can sign in", "acceptanceCriteria": "Valid credentials open the orders page."}' \ | jq -r .id)"Add a test with its procedure:
curl -sS --fail-with-body "$TANDA_API/criteria/$TANDA_CRITERION_ID/tests" \ -H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' \ -d '{ "title": "Sign in with valid credentials", "testType": "manual", "priority": "high", "testFormat": "procedural", "sections": [{ "title": "Execution", "functions": [{ "title": "Sign in", "prerequisites": "An active customer account exists", "steps": [ {"step": 1, "action": "Open /signin", "expected": "The sign-in form shows"}, {"step": 2, "action": "Submit valid credentials", "expected": "The orders page opens"} ] }] }] }' | jq '{id, title}'Create a SOW called Phase 1 in Customer portal from this brief: customers sign in and see their orders. Add task items, acceptance criteria and a detailed test for each criterion.
The assistant calls
create_sow,create_task_item,create_acceptance_criterionandcreate_test. For a long brief, ask it to usestart_sow_generationinstead, which drafts the SOW and waits for your approval before saving.To find what’s missing, ask it to check coverage. It calls
analyze_coverage.Produce the ATP
An ATP isn’t a separate record. Tanda generates it from the SOW, so it always matches the current tests. A criterion with no test has nothing to run, so check that every criterion has one.
As Markdown, or as a PDF to send to your client:
curl -sS --fail-with-body \ "$TANDA_APP/api/sow/$TANDA_SOW_ID/export?format=markdown&variant=procedure" \ -H "Authorization: Bearer $TANDA_TOKEN" curl -sS --fail-with-body -o atp.pdf \ "$TANDA_APP/api/sow/$TANDA_SOW_ID/export?format=pdf&variant=procedure" \ -H "Authorization: Bearer $TANDA_TOKEN"Once tests have run,
variant=reportadds their results.Give me the acceptance test plan for Phase 1.
The assistant calls
get_acceptance_test_plan, which returns the plan as Markdown, along with any criteria that have no test. For a PDF, use the Terminal route or export it from the SOW in the app.
Accepting an invitation
Organization invitation. Open the acceptUrl and sign in with the invited address. To do it from a terminal, sign in so you have a session, then use the value after invitation= in the link:
curl -sS --fail-with-body -b "$TANDA_JAR" "$TANDA_APP/api/organization-settings" \
-H "Origin: $TANDA_APP" -H 'Content-Type: application/json' \
-d "$(jq -n --arg id "$TANDA_INVITATION" '{action: "accept", invitationId: $id}')"Then set the organization active, as in step 2, to create a token for it. A token belongs to the organization that was active when it was made.
Project invitation. Open the link, or use the value after token= with an API token from an account with the invited email address. The request must send a JSON body, even an empty one:
curl -sS --fail-with-body "$TANDA_API/project-invitations/$TANDA_INVITE_TOKEN/accept" \
-H "Authorization: Bearer $TANDA_TOKEN" -H 'Content-Type: application/json' -d '{}'If something fails
| You see | What it means | What to do |
|---|---|---|
401 from the REST API |
The token is missing, wrong or revoked | Check Authorization: Bearer tnda_..., or create a new token |
401 from /mcp |
tnda_ tokens don’t work on the MCP server |
Connect through your client’s sign-in |
403 Access denied |
You don’t have access to that record, or it’s in another organization | Use a token from the organization that owns it, or ask an owner to invite you |
403 Invalid origin |
A session request has no matching Origin header |
Send Origin: https://www.testandaccept.com |
400 Organization required |
No organization is active for this session | Finish step 2 first |
409 on a criterion or test |
The SOW version is locked after approval | Change it through an RFC |
415 Missing content-type header |
A POST has no JSON body |
Send Content-Type: application/json and -d '{}' |
429 |
Too many attempts | Wait 10 seconds and try again |
Unsupported protocol version |
Your MCP client is too old for the server | Use the Terminal route (Pi details) |