Skip to main content
Use this tutorial after Quickstart with TypeScript SDK or Quickstart with MCP when you want to see the full Shodai agreement lifecycle work with a realistic agreement before authoring your own. You will run the service retainer example from authored agreement JSON through validation, deployment preflight, signed deployment, signed input submission, state reads, and input-history inspection. The service retainer is the teaching artifact for this tutorial. It is useful because it has participant roles, initialized business values, branching states, authorized inputs, EIP-712 signatures, state transitions, and an auditable history. You do not need to be building a retainer product to learn from it.

What you will learn

By the end of this workflow, you will have seen how:
  • authored agreement JSON defines variables, participants, states, inputs, issuers, and transitions
  • deployment context supplies live values such as participant wallets, chainId, and initialization data
  • deployment preflight normalizes the values that must be signed
  • EIP-712 permits authorize deployment and input submission
  • submitted inputs move an agreement through its authored state machine
  • state and input history provide receipts for what happened

Before you start

This tutorial has two equivalent paths. Use the MCP path when an agent is operating Shodai through MCP tools. Use the SDK path when you are building the workflow into a TypeScript integration.
RequirementMCP pathSDK path
API accessA Shodai API key configured for the hosted MCP server.A Shodai API key passed to ApiClient.
Example agreementThe complex-example-agreement MCP resource.The complete JSON from Complex Agreement.
Environmentenvironment: "testnet" for a testnet key, or environment: "production" for a production key.new ApiClient({ environment: "testnet", apiKey }) for testnet.
Permit signerAn external signer that can sign returned EIP-712 typed data.A walletClient that can sign with the intended account.
For setup details, see Quickstart with TypeScript SDK, Quickstart with MCP, TypeScript client reference, Authentication, and Complex Agreement.
Use testnet for a first run. Deployment and input submission are writes. They require signatures from eligible wallets, and successful submissions are not safe to retry blindly.
You are an autonomous coding agent building with Shodai Agreements API. Start from the user's current context; if they already have a project, API key, agreement ID, error response, MCP tools, or clear task, skip generic onboarding and work from there.

First load documentation context:
1. Fetch https://docs.shodai.network/llms.txt and use it as the canonical page index.
2. Fetch https://docs.shodai.network/skill.md for agent workflow constraints.
3. Read the relevant page-level Markdown exports:
   - https://docs.shodai.network/integration-surfaces.md
   - https://docs.shodai.network/sdks/quickstart-with-typescript-sdk.md
   - https://docs.shodai.network/sdks/quickstart-with-mcp.md
   - https://docs.shodai.network/sdks/typescript-client.md
   - https://docs.shodai.network/authentication.md
   - https://docs.shodai.network/examples/complex.md
   - https://docs.shodai.network/workflow/validate-agreement-structure.md
   - https://docs.shodai.network/workflow/deploy-an-agreement.md
   - https://docs.shodai.network/workflow/operate-a-deployed-agreement.md
   - https://docs.shodai.network/reference/eip-712-signing.md
   - https://docs.shodai.network/reference/errors-and-troubleshooting.md
4. Fetch https://docs.shodai.network/openapi.json before composing raw routes, request bodies, response-status assertions, or payload schemas.
5. Use https://docs.shodai.network/llms-full.txt only as broad fallback context.

Choose the operating mode:
- Use MCP when MCP tools or MCP client context are available.
- Use the TypeScript SDK when building or testing a TypeScript integration.
- Do not force a temporary TypeScript project when operating through MCP.
- If no signing infrastructure exists and the user wants to continue past typed-data preparation, use the TypeScript SDK with viem as the local testnet signing harness.

Use complete docs examples, not abbreviated API reference snippets. Do not invent API routes, request bodies, agreement JSON, state IDs, input IDs, issuer rules, lifecycle behavior, nonce handling, or signing payloads.

Perform the workflow:
1. Confirm API or MCP authentication.
2. Load the complete service retainer agreement from https://docs.shodai.network/examples/complex.md or the complex-example-agreement MCP resource.
3. Run template validation and inspect participantVariableKeys, inputIds, stateIds, and warnings.
4. Prepare deployment context with testnet chain, participant wallet addresses, init values, and observers when needed.
5. Run deployment preflight before signing. Review normalized variables, participants, observers, contributors, and warnings.
6. Prepare or sign the deployment permit using the selected operating mode.
7. Deploy only when credentials, signing context, and user intent permit a live write.
8. Read the deployed agreement record and current state.
9. Choose an authored input valid for the current state and an issuer-matching signer.
10. Prepare or sign the input permit, then submit the input only when live writes are intended.
11. Reread state and input history. Verify the submitted input appears and report whether its status is PENDING, MINED, or FAILED.
12. If blocked, troubleshoot from Shodai docs before asking the human, except for missing credentials, signing authority, or access.

Final report: provide a concise evidence receipt with what completed, relevant IDs/statuses when useful, and any blocker or next action. Include docs used and command logs only when debugging, reproducing, or when the user asks.

Choose a path

Both paths use the same lifecycle and the same underlying API model. The difference is the surface you operate through.
Lifecycle stepMCP toolSDK method or helper
Validate authored JSONvalidate_agreementclient.validateTemplate(...)
Preflight deploymentpreflight_deploymentclient.validateDeployment(...)
Prepare or create deploy permitprepare_deployment_typed_datadeployAgreementWithPermit(...) or signDeployWithPermit(...)
Deploy with permitdeploy_agreementdeployAgreementWithPermit(...) or client.deployWithPermit(...)
Read current stateget_agreement_stateclient.getAgreementState(...)
Prepare or create input permitprepare_input_typed_datasubmitAgreementInputWithPermit(...) or signAgreementInputPermit(...)
Submit signed inputsubmit_inputsubmitAgreementInputWithPermit(...) or client.submitAgreementInput(...)
Inspect input historyget_input_historyclient.listAgreementInputs(...)

Run the workflow

1

Load the service retainer example

Read the complex-example-agreement MCP resource.The resource URI is:
agreements://examples/complex-agreement.json
MCP resources return JSON as text. Parse the returned contents[0].text value and keep the parsed object as agreement for the remaining MCP tool calls.This is the same agreement documented in Complex Agreement. It starts in AWAITING_PAYMENT, moves to WORK_IN_PROGRESS after initial payment proof, supports invoice review paths, can branch into top-up review, and can terminate through a final invoice flow.
2

Validate the authored agreement JSON

Call validate_agreement with the API environment that matches your key and pass the parsed complex-example-agreement object as agreement.Review the validation result before continuing. The important evidence is the participant variable keys, state IDs, input IDs, and warnings. For this example, expect participant-backed variables such as serviceProviderRepresentative and clientRepresentative, and lifecycle inputs such as submitInitialPaymentProof and submitInvoice.Structural validation checks the agreement artifact only. It does not know which wallets or initialization values you will use for deployment.
3

Prepare deployment values

Choose deployment context for the first run.
FieldExample valueWhy it matters
chainId59141Selects Linea Sepolia for a testnet deployment.
displayNameService Retainer TutorialNames the hosted agreement record.
serviceProviderRepresentativetest wallet addressAuthorizes service-provider inputs.
clientRepresentativetest wallet addressAuthorizes client inputs.
retainerTitleService Retainer TutorialInitializes rendered agreement content.
retainerDescriptionA tutorial agreement used to learn the Shodai lifecycle.Initializes rendered agreement content.
serviceProviderNameProvider LLCInitializes rendered agreement content.
clientNameClient IncInitializes rendered agreement content.
retainerCeiling1000Initializes business data used by the example.
retainerFloor200Initializes business data used by the example.
paymentInstructionsRecord payment proof using a testnet transaction or placeholder proof URL.Initializes rendered payment instructions.
Keep participant wallet mappings and initialization values stable after preflight. If they change, regenerate the deployment typed data before signing.
4

Preflight deployment

Call preflight_deployment with the loaded agreement object, target chain, initialization values, and participant mappings.Use this deployment context with the loaded agreement:
{
  "environment": "testnet",
  "chainId": 59141,
  "initValues": {
    "retainerTitle": "Service Retainer Tutorial",
    "retainerDescription": "A tutorial agreement used to learn the Shodai lifecycle.",
    "serviceProviderName": "Provider LLC",
    "clientName": "Client Inc",
    "retainerCeiling": 1000,
    "retainerFloor": 200,
    "paymentInstructions": "Record payment proof using a testnet transaction or placeholder proof URL."
  },
  "participants": [
    {
      "variableKey": "serviceProviderRepresentative",
      "walletAddress": "0x1111111111111111111111111111111111111111"
    },
    {
      "variableKey": "clientRepresentative",
      "walletAddress": "0x2222222222222222222222222222222222222222"
    }
  ]
}
Review the returned variables, participants, observers, contributors, and warnings before any signing step.
Preflight does not deploy the agreement. It assembles and validates the deployment request so you can sign the effective values rather than raw caller input.
5

Sign and deploy

For hosted MCP with external signing, call prepare_deployment_typed_data, sign the returned EIP-712 payload, then call deploy_agreement with the returned document link, normalized values, and permit fields.Call prepare_deployment_typed_data with:
  • environment: "testnet"
  • agreement: the loaded complex-example-agreement object
  • chainId: 59141
  • signerAddress: the wallet address that will sign and own the deployment
  • initValues: the same values used for preflight
  • participants: the same participant mappings used for preflight
prepare_deployment_typed_data
-> sign returned EIP-712 typed data externally
-> deploy_agreement
Pass the same agreement, displayName, and chainId; the returned docUri and documentId when present; the normalizedInitValues, normalizedParticipants, and normalizedObservers returned by prepare_deployment_typed_data; and signer address, deadline, and signature fields into deploy_agreement.
Do not sign one deployment payload and submit another. Agreement JSON, initialization values, participant mappings, docUri, chain, factory context, nonce, and deadline are all part of the authorization boundary.
6

Read the deployed state

After deployment, call get_agreement_state.
{
  "environment": "testnet",
  "agreementId": "<deployed agreement id>"
}
The service retainer starts at AWAITING_PAYMENT. The current state tells you which authored inputs can move the lifecycle next.
7

Submit the first lifecycle input

Submit submitInitialPaymentProof to move the retainer from AWAITING_PAYMENT to WORK_IN_PROGRESS.First call prepare_input_typed_data with an eligible signer and the input values.
{
  "environment": "testnet",
  "agreementId": "<deployed agreement id>",
  "inputId": "submitInitialPaymentProof",
  "values": {
    "awaitingPaymentPaymentLink": "https://sepolia.lineascan.build/tx/0xexample",
    "awaitingPaymentComment": "Initial payment proof recorded for the tutorial run."
  },
  "signerAddress": "0x2222222222222222222222222222222222222222"
}
Sign the returned EIP-712 typed data externally, then call submit_input with the same agreementId, inputId, values, signer address, deadline, and signature fields.The submitInitialPaymentProof input can be issued by either representative in the service retainer example. Later inputs may be restricted to one role.
8

Inspect state and history

Reread current state and input history.
get_agreement_state
get_input_history
Use state to confirm the lifecycle position and input history to confirm that the submitted input appears with its status. Depending on transaction timing, an input may be PENDING, MINED, or FAILED.

Try a branch

After the agreement reaches WORK_IN_PROGRESS, try one additional path to see why the complex example is useful.
Submit the submitInvoice input from WORK_IN_PROGRESS. The service provider representative must sign this input.Required values:
{
  "retainerBalanceBeforeInvoice": 1000,
  "invoiceLineItems": "2026-04-01,Advisory services,10,100,1000",
  "submitInvoiceComment": "Invoice submitted for April services."
}
This path moves the agreement to INVOICE_SUBMITTED. From there, an authorized representative can approve, reject with feedback, or initiate termination.
Submit the submitInvoiceWithTopup input from WORK_IN_PROGRESS. The service provider representative must sign this input.Required values:
{
  "retainerBalanceBeforeInvoice": 300,
  "invoiceLineItems": "2026-04-01,Advisory services,10,100,1000",
  "topupInvoiceComment": "Invoice submitted with top-up request."
}
This path moves the agreement to INVOICE_SUBMITTED_WITH_TOPUP. The next step can approve with payment proof, reject with feedback, or initiate termination.

What happened under the hood

This tutorial uses one concrete agreement to exercise the core Shodai model.
Tutorial actionSystem conceptWhere to learn more
Load the service retainer JSONAgreement JSON defines the readable content and executable lifecycle.Agreement data standard
Validate templateStructural validation checks authored variables, states, inputs, issuers, and transitions.Validate Agreement Structure
Add participant wallets and initValuesDeployment context binds the reusable agreement template to live parties and values.Deploy an Agreement
Preflight before signingPreflight normalizes effective values and catches deployment issues before authorization.Deploy an Agreement
Sign deployment and input permitsEIP-712 signatures prove that an eligible wallet authorized the write.EIP-712 Signing Reference
Submit submitInitialPaymentProofInputs are signed lifecycle events accepted only from allowed issuers.Author Agreement JSON
Reread state and input historyState shows the current lifecycle position; history shows the submitted event trail.Operate a Deployed Agreement

If a step fails

Use Errors and troubleshooting for API errors, signing failures, and lifecycle diagnostics. Before retrying a write, reread state and input history so you do not sign or submit against a stale lifecycle position.

Next steps

Inspect the complex agreement

Study the complete service retainer JSON, lifecycle diagram, states, inputs, and transitions.

Author your own agreement

Turn a business workflow into agreement JSON after you have run the lifecycle once.

Build with the SDK

Use the TypeScript client reference for typed API calls, signing helpers, and diagnostics.

Quickstart with MCP

Configure the hosted MCP server and operate agreements through MCP tools.