{
  "schemaVersion": "1.0",
  "title": "Run the Twenty connector quickstart",
  "description": "In this tutorial, you will read one Twenty collection and create one record through an already admitted connector. You will then read the original AIP Action until its governed mutation reaches a terminal state.",
  "canonical": "https://getaip.org/docs/connectors/twenty/getting-started/quickstart",
  "route": "/docs/connectors/twenty/getting-started/quickstart",
  "source": "docs/connectors/twenty/getting-started/quickstart.md",
  "protocol": "Agent Interoperability Protocol",
  "protocolVersion": "1.0",
  "section": "Connectors",
  "documentType": "Connector",
  "language": "en",
  "downloads": {
    "md": "/docs/download/connectors/twenty/getting-started/quickstart.md",
    "txt": "/docs/download/connectors/twenty/getting-started/quickstart.txt",
    "json": "/docs/download/connectors/twenty/getting-started/quickstart.json",
    "pdf": "/docs/download/connectors/twenty/getting-started/quickstart.pdf"
  },
  "content": {
    "format": "text/markdown",
    "markdown": "---\ntitle: Run the Twenty connector quickstart\ndescription: >-\n  Read one workspace collection, create one deterministic record under\n  approval, and verify the durable AIP result\nkind: tutorial\naudience: application-developer\nappliesTo: \"1.x\"\nwritingStandard: \"aip-docs/1.0\"\nlastReviewedRevision: \"97be86e9efedf07ecf1783b03800f683f107fb04\"\nconnector: twenty\ncapabilityIds:\n  - cap:twenty:record.list\n  - cap:twenty:record.create\n---\n\n# Run the Twenty connector quickstart\n\nIn this tutorial, you will read one Twenty collection and create one record\nthrough an already admitted connector. You will then read the original AIP\nAction until its governed mutation reaches a terminal state.\n\nThe example uses a standard `companies` object. Confirm that this object and\nits `name` field exist in the admitted workspace before submitting the create.\n\nThis procedure does not deploy Twenty or the connector. The reviewed fleet\nCompose file has no Twenty service, so the tutorial starts from a deployment\nwhose operator has already admitted and connected the host.\n\n## What you will verify\n\nBy the end, you will have observed:\n\n- two admitted fixed capabilities rather than an arbitrary provider route;\n- a read scoped to the host's configured workspace and credential;\n- one create held for tenant-policy approval;\n- a stable idempotency key bound to the create input;\n- a connector-generated deterministic record ID when the input omits `id`;\n- the same queued Action resuming after approval;\n- a durable terminal result containing the provider HTTP status and body.\n\nYou will not test webhook delivery, metadata mutation, batch operations,\ndeletion, restore, merge, failover, or a connector deployment.\n\n## Prerequisites\n\nYou need:\n\n- a reachable native AIP endpoint;\n- an admitted Twenty host bound to the intended workspace;\n- an AIP caller credential authorized for discovery and invocation;\n- a trusted tenant approver for mutations;\n- permission to create the named fixture in that workspace;\n- a durable place to retain Action, approval, and idempotency identities;\n- `aipctl` built from the reviewed AIP revision.\n\nSet only AIP client coordinates in the shell:\n\n```sh\nexport AIP_URL='https://aip.example.com'\nexport AIP_TOKEN_FILE='/run/secrets/aip-native-token'\n```\n\nThe operator configures the Twenty origin, workspace UUID, and API token on the\nhost. Do not put the provider token or workspace selector in Action input.\n\n## 1. Confirm the admitted contracts\n\nDiscover the two capabilities used by this tutorial:\n\n```sh\naipctl \\\n  --native-bearer-token-file \"$AIP_TOKEN_FILE\" \\\n  capability list \"$AIP_URL\" \\\n  --capability-id cap:twenty:record.list \\\n  --limit 1\n\naipctl \\\n  --native-bearer-token-file \"$AIP_TOKEN_FILE\" \\\n  capability list \"$AIP_URL\" \\\n  --capability-id cap:twenty:record.create \\\n  --limit 1\n```\n\nRecord the catalog revision plus both contract and schema digests. Confirm that\n`record.list` is a retry-safe read. Confirm that `record.create` requires\napproval and external-account idempotency with a seven-day contract TTL.\n\nCatalog visibility proves admission at one revision. It does not prove current\nprovider reachability or that the workspace still exposes the example object.\n\n## 2. Read a bounded collection\n\nWrite `companies-list.json`:\n\n```json\n{\n  \"object\": \"companies\",\n  \"query\": {\n    \"limit\": 1\n  }\n}\n```\n\nSubmit a synchronous read with a stable Action ID:\n\n```sh\nexport LIST_ACTION_ID='act_twenty_quickstart_list_001'\n\naipctl \\\n  --native-bearer-token-file \"$AIP_TOKEN_FILE\" \\\n  action call \"$AIP_URL\" \\\n  cap:twenty:record.list \\\n  --action-id \"$LIST_ACTION_ID\" \\\n  --mode sync \\\n  --input @companies-list.json\n```\n\nA completed result contains `http_status`, an optional\n`provider_request_id`, and the provider `body`. The connector does not reshape\nthe collection into an AIP-specific record model.\n\nStop if this read reports authentication, object, or schema failure. Correct\nthe deployment or select a workspace-owned object before attempting a write.\n\n## 3. Freeze one create intent\n\nWrite `company-create.json` once:\n\n```json\n{\n  \"object\": \"companies\",\n  \"body\": {\n    \"name\": \"AIP Quickstart Company\"\n  }\n}\n```\n\nThe connector accepts standard and custom object names that match its bounded\nidentifier grammar. Twenty still decides whether the selected object and body\nmatch the current workspace schema.\n\nReserve stable identities for this exact input:\n\n```sh\nexport CREATE_ACTION_ID='act_twenty_quickstart_create_001'\nexport CREATE_KEY='twenty-quickstart-company-v1'\n```\n\nKeep the Action ID, key, object, and body unchanged. Reusing the key with\ndifferent canonical input is an idempotency collision, not a new create.\n\n## 4. Submit the governed create\n\nSubmit the mutation once:\n\n```sh\naipctl \\\n  --native-bearer-token-file \"$AIP_TOKEN_FILE\" \\\n  action call \"$AIP_URL\" \\\n  cap:twenty:record.create \\\n  --action-id \"$CREATE_ACTION_ID\" \\\n  --idempotency-key \"$CREATE_KEY\" \\\n  --mode sync \\\n  --input @company-create.json\n```\n\nWithout an admitted approval decision, the Action enters `requires_human` and\nreturns an approval identity. Store that identity and leave the original\nAction in place.\n\nThe connector forces provider `upsert=true`. When the body omits `id`, it\nderives one UUID from the configured workspace, idempotency key, and record\nindex. This makes a repeated create target the same provider record.\n\nDeterministic targeting limits duplicate risk. It does not authorize the\nmutation or prove that Twenty committed the upsert.\n\n## 5. Complete trusted approval\n\nUse the deployment's approver-facing process to inspect the frozen request and\nsubmit a decision from an authenticated tenant-policy authority. The decision\nmust match the approval ID and policy hash and provide the required reason,\ninput snapshot, and policy-decision evidence.\n\nThe Twenty approval validity window is 900,000 ms. Approval resumes the same\nqueued Action. Do not submit a replacement create or change the idempotency key\nwhile the original Action remains pending.\n\nApproval authorizes one attempt of the frozen intent. It does not establish\nprovider success, schema compatibility, or safe replay after an uncertain\nmutation outcome.\n\n## 6. Read the durable result\n\nRead the original Action independently of its submission connection:\n\n```sh\naipctl \\\n  --native-bearer-token-file \"$AIP_TOKEN_FILE\" \\\n  action status \"$AIP_URL\" \\\n  \"$CREATE_ACTION_ID\" \\\n  --include-result \\\n  --include-receipts \\\n  --wait-ms 30000\n```\n\nProceed only after a terminal `completed` result. Verify a successful\n`http_status`, retain `provider_request_id` when present, and inspect the\nreturned body for the deterministic record ID and intended name.\n\nTreat a nonterminal Action as still owned by the original workflow. Treat an\nuncertain mutation failure as a reconciliation case; changing the Action ID or\nkey can create an additional provider effect.\n\n## 7. Confirm idempotent observation\n\nRepeat the exact create request with the same Action ID, key, and bytes:\n\n```sh\naipctl \\\n  --native-bearer-token-file \"$AIP_TOKEN_FILE\" \\\n  action call \"$AIP_URL\" \\\n  cap:twenty:record.create \\\n  --action-id \"$CREATE_ACTION_ID\" \\\n  --idempotency-key \"$CREATE_KEY\" \\\n  --mode sync \\\n  --input @company-create.json\n```\n\nExpected result: the runtime returns the durable outcome for the same AIP\nintent. This check is not permission to send a new Action with a new key.\n\n## Recover without duplicating the write\n\n| Observation | Response |\n|---|---|\n| Capability is absent | Stop; the operation is not admitted for this route |\n| Read returns authentication failure | Repair host credential or workspace binding; do not add credentials to input |\n| Create is `requires_human` | Complete the existing approval workflow |\n| Create remains pending | Read the same Action; do not replace it |\n| `connector.twenty.invalid_request` | Correct object, body, identifier, or key under a new governed intent |\n| `connector.twenty.remote_rejected` | Inspect redacted provider details and current workspace schema |\n| Temporary read failure | Retry the read according to its contract |\n| Uncertain mutation failure | Preserve the original Action and key; reconcile before any new write |\n\nThe connector has no cancellation, transaction, compensation, or automatic\nprovider-reconciliation operation. A caller cannot turn an uncertain create\ninto a safe retry by replacing its identity.\n\n## Verify the tutorial outcome\n\nRetain and compare:\n\n- the catalog revision plus both contract and schema digests;\n- the list Action and its bounded input;\n- the immutable create input, Action ID, and idempotency key;\n- the approval ID, policy hash, decision, and required evidence;\n- the terminal Action result and receipts;\n- the provider request ID and returned record ID when present.\n\nThese artifacts demonstrate one governed application path. They do not by\nthemselves establish live-provider qualification, production readiness,\nwebhook delivery, external notification, or compatibility with another Twenty\nrevision.\n\n## Related documentation\n\n- [Twenty connector overview](../README.md)\n- [AIP quickstart](../../../getting-started/quickstart.md)\n- [Command-line interface](../../../reference/cli.md)\n- [Approvals and policy](../../../concepts/approvals-and-policy.md)\n- [Errors and retry decisions](../../../reference/errors.md)\n",
    "text": "Run the Twenty connector quickstart\n\nIn this tutorial, you will read one Twenty collection and create one record\nthrough an already admitted connector. You will then read the original AIP\nAction until its governed mutation reaches a terminal state.\n\nThe example uses a standard companies object. Confirm that this object and\nits name field exist in the admitted workspace before submitting the create.\n\nThis procedure does not deploy Twenty or the connector. The reviewed fleet\nCompose file has no Twenty service, so the tutorial starts from a deployment\nwhose operator has already admitted and connected the host.\n\nWhat you will verify\n\nBy the end, you will have observed:\n• two admitted fixed capabilities rather than an arbitrary provider route;\n• a read scoped to the host's configured workspace and credential;\n• one create held for tenant-policy approval;\n• a stable idempotency key bound to the create input;\n• a connector-generated deterministic record ID when the input omits id;\n• the same queued Action resuming after approval;\n• a durable terminal result containing the provider HTTP status and body.\n\nYou will not test webhook delivery, metadata mutation, batch operations,\ndeletion, restore, merge, failover, or a connector deployment.\n\nPrerequisites\n\nYou need:\n• a reachable native AIP endpoint;\n• an admitted Twenty host bound to the intended workspace;\n• an AIP caller credential authorized for discovery and invocation;\n• a trusted tenant approver for mutations;\n• permission to create the named fixture in that workspace;\n• a durable place to retain Action, approval, and idempotency identities;\n• aipctl built from the reviewed AIP revision.\n\nSet only AIP client coordinates in the shell:\n\nexport AIPURL='https://aip.example.com'\nexport AIPTOKENFILE='/run/secrets/aip-native-token'\n\nThe operator configures the Twenty origin, workspace UUID, and API token on the\nhost. Do not put the provider token or workspace selector in Action input.\n1. Confirm the admitted contracts\n\nDiscover the two capabilities used by this tutorial:\n\naipctl \\\n  --native-bearer-token-file \"$AIPTOKENFILE\" \\\n  capability list \"$AIPURL\" \\\n  --capability-id cap:twenty:record.list \\\n  --limit 1\n\naipctl \\\n  --native-bearer-token-file \"$AIPTOKENFILE\" \\\n  capability list \"$AIPURL\" \\\n  --capability-id cap:twenty:record.create \\\n  --limit 1\n\nRecord the catalog revision plus both contract and schema digests. Confirm that\nrecord.list is a retry-safe read. Confirm that record.create requires\napproval and external-account idempotency with a seven-day contract TTL.\n\nCatalog visibility proves admission at one revision. It does not prove current\nprovider reachability or that the workspace still exposes the example object.\n2. Read a bounded collection\n\nWrite companies-list.json:\n\n{\n  \"object\": \"companies\",\n  \"query\": {\n    \"limit\": 1\n  }\n}\n\nSubmit a synchronous read with a stable Action ID:\n\nexport LISTACTIONID='acttwentyquickstartlist001'\n\naipctl \\\n  --native-bearer-token-file \"$AIPTOKENFILE\" \\\n  action call \"$AIPURL\" \\\n  cap:twenty:record.list \\\n  --action-id \"$LISTACTIONID\" \\\n  --mode sync \\\n  --input @companies-list.json\n\nA completed result contains httpstatus, an optional\nproviderrequestid, and the provider body. The connector does not reshape\nthe collection into an AIP-specific record model.\n\nStop if this read reports authentication, object, or schema failure. Correct\nthe deployment or select a workspace-owned object before attempting a write.\n3. Freeze one create intent\n\nWrite company-create.json once:\n\n{\n  \"object\": \"companies\",\n  \"body\": {\n    \"name\": \"AIP Quickstart Company\"\n  }\n}\n\nThe connector accepts standard and custom object names that match its bounded\nidentifier grammar. Twenty still decides whether the selected object and body\nmatch the current workspace schema.\n\nReserve stable identities for this exact input:\n\nexport CREATEACTIONID='acttwentyquickstartcreate001'\nexport CREATEKEY='twenty-quickstart-company-v1'\n\nKeep the Action ID, key, object, and body unchanged. Reusing the key with\ndifferent canonical input is an idempotency collision, not a new create.\n4. Submit the governed create\n\nSubmit the mutation once:\n\naipctl \\\n  --native-bearer-token-file \"$AIPTOKENFILE\" \\\n  action call \"$AIPURL\" \\\n  cap:twenty:record.create \\\n  --action-id \"$CREATEACTIONID\" \\\n  --idempotency-key \"$CREATEKEY\" \\\n  --mode sync \\\n  --input @company-create.json\n\nWithout an admitted approval decision, the Action enters requireshuman and\nreturns an approval identity. Store that identity and leave the original\nAction in place.\n\nThe connector forces provider upsert=true. When the body omits id, it\nderives one UUID from the configured workspace, idempotency key, and record\nindex. This makes a repeated create target the same provider record.\n\nDeterministic targeting limits duplicate risk. It does not authorize the\nmutation or prove that Twenty committed the upsert.\n5. Complete trusted approval\n\nUse the deployment's approver-facing process to inspect the frozen request and\nsubmit a decision from an authenticated tenant-policy authority. The decision\nmust match the approval ID and policy hash and provide the required reason,\ninput snapshot, and policy-decision evidence.\n\nThe Twenty approval validity window is 900,000 ms. Approval resumes the same\nqueued Action. Do not submit a replacement create or change the idempotency key\nwhile the original Action remains pending.\n\nApproval authorizes one attempt of the frozen intent. It does not establish\nprovider success, schema compatibility, or safe replay after an uncertain\nmutation outcome.\n6. Read the durable result\n\nRead the original Action independently of its submission connection:\n\naipctl \\\n  --native-bearer-token-file \"$AIPTOKENFILE\" \\\n  action status \"$AIPURL\" \\\n  \"$CREATEACTIONID\" \\\n  --include-result \\\n  --include-receipts \\\n  --wait-ms 30000\n\nProceed only after a terminal completed result. Verify a successful\nhttpstatus, retain providerrequestid when present, and inspect the\nreturned body for the deterministic record ID and intended name.\n\nTreat a nonterminal Action as still owned by the original workflow. Treat an\nuncertain mutation failure as a reconciliation case; changing the Action ID or\nkey can create an additional provider effect.\n7. Confirm idempotent observation\n\nRepeat the exact create request with the same Action ID, key, and bytes:\n\naipctl \\\n  --native-bearer-token-file \"$AIPTOKENFILE\" \\\n  action call \"$AIPURL\" \\\n  cap:twenty:record.create \\\n  --action-id \"$CREATEACTIONID\" \\\n  --idempotency-key \"$CREATEKEY\" \\\n  --mode sync \\\n  --input @company-create.json\n\nExpected result: the runtime returns the durable outcome for the same AIP\nintent. This check is not permission to send a new Action with a new key.\n\nRecover without duplicating the write\n\n| Observation | Response |\n\n| Capability is absent | Stop; the operation is not admitted for this route |\n| Read returns authentication failure | Repair host credential or workspace binding; do not add credentials to input |\n| Create is requireshuman | Complete the existing approval workflow |\n| Create remains pending | Read the same Action; do not replace it |\n| connector.twenty.invalidrequest | Correct object, body, identifier, or key under a new governed intent |\n| connector.twenty.remoterejected | Inspect redacted provider details and current workspace schema |\n| Temporary read failure | Retry the read according to its contract |\n| Uncertain mutation failure | Preserve the original Action and key; reconcile before any new write |\n\nThe connector has no cancellation, transaction, compensation, or automatic\nprovider-reconciliation operation. A caller cannot turn an uncertain create\ninto a safe retry by replacing its identity.\n\nVerify the tutorial outcome\n\nRetain and compare:\n• the catalog revision plus both contract and schema digests;\n• the list Action and its bounded input;\n• the immutable create input, Action ID, and idempotency key;\n• the approval ID, policy hash, decision, and required evidence;\n• the terminal Action result and receipts;\n• the provider request ID and returned record ID when present.\n\nThese artifacts demonstrate one governed application path. They do not by\nthemselves establish live-provider qualification, production readiness,\nwebhook delivery, external notification, or compatibility with another Twenty\nrevision.\n\nRelated documentation\n• Twenty connector overview (../README.md)\n• AIP quickstart (../../../getting-started/quickstart.md)\n• Command-line interface (../../../reference/cli.md)\n• Approvals and policy (../../../concepts/approvals-and-policy.md)\n• Errors and retry decisions (../../../reference/errors.md)\n"
  },
  "integrity": {
    "algorithm": "sha256",
    "sourceDigest": "71b97ceb201db9743dcd9bcf682a82c6526c7775f23b2255cf4d5c4830ca4aae"
  }
}
