Skip to content
AIPDocs
Release status
DocumentationAIP 1.0ConnectorConnectors

Manage Twenty views, layouts, and webhook metadata

Use this guide to change one view, page-layout hierarchy, or provider webhook registration. Begin with the current workspace metadata schema and dependency graph, submit one critical mutation, then verify the provider result through a separate read.

The connector validates the selected resource, outer input, parent query, and webhook-secret boundary. Twenty owns resource-specific body fields, relationships, cascades, and the resulting user experience.

Prerequisites

Require:

  • an admitted Twenty host bound to the intended tenant and workspace;
  • authenticated access to metadata OpenAPI and the needed metadata operations;
  • an integrator who owns the affected object, view, layout, or webhook;
  • a trusted tenant approver for critical metadata changes;
  • a current provider backup or recovery plan for the affected metadata;
  • a durable place for schema, dependency, Action, approval, and result evidence;
  • coordinated host and provider ownership for webhook registration or rotation.

Set only AIP client coordinates:

export AIP_URL='https://aip.example.com'
export AIP_TOKEN_FILE='/run/secrets/aip-native-token'

Provider credentials and webhook secret bytes remain host-owned.

1. Confirm the admitted operations

Discover the metadata Resources and Tools used by the intended change:

aipctl \
  --native-bearer-token-file "$AIP_TOKEN_FILE" \
  capability list "$AIP_URL" \
  --capability-id cap:twenty:openapi.metadata \
  --limit 1

aipctl \
  --native-bearer-token-file "$AIP_TOKEN_FILE" \
  capability list "$AIP_URL" \
  --capability-id cap:twenty:metadata.list \
  --limit 1

aipctl \
  --native-bearer-token-file "$AIP_TOKEN_FILE" \
  capability list "$AIP_URL" \
  --capability-id cap:twenty:metadata.update \
  --limit 1

Use metadata.create or metadata.delete instead of update when that is the actual intent. Record catalog revision and every selected contract and schema digest.

Stop when an operation is absent. Do not widen the host allowlist during an active change merely to satisfy the procedure.

2. Capture the metadata schema

Read cap:twenty:openapi.metadata with {}. Retain the body under tenant-scoped controls and calculate its digest outside the connector.

Record connector artifact, pinned provider mapping, instance, tenant, workspace, credential revision, Action ID, observation time, HTTP status, and provider request ID.

Extract only the provider fields needed for the chosen resource. Freeze their required status, types, enums, identifiers, parent references, and delete behavior as the change’s body contract.

The connector accepts an arbitrary object body with at most 2,048 top-level properties. It does not validate that body against the observed provider document.

3. Snapshot the current dependency graph

Use metadata.list and metadata.get before any mutation. The exact reads depend on the resource family.

Snapshot a view

Start with the owning object and view:

{
  "resource": "views",
  "query": {
    "objectMetadataId": "0190c42f-2d5a-7000-8000-000000000070"
  }
}

For each selected view, list these children using its UUID as viewId:

  • viewFields;
  • viewFilters;
  • viewGroups;
  • viewSorts;
  • viewFilterGroups.

The connector permits an omitted viewId, but a change review should retain a bounded parent-specific snapshot.

Snapshot a page-layout hierarchy

List layouts by object and optional type:

{
  "resource": "pageLayouts",
  "query": {
    "objectMetadataId": "0190c42f-2d5a-7000-8000-000000000070",
    "pageLayoutType": "RECORD_PAGE"
  }
}

Allowed types are RECORD_INDEX, RECORD_PAGE, DASHBOARD, and STANDALONE_PAGE. The connector rejects a type without objectMetadataId.

List tabs under one layout:

{
  "resource": "pageLayoutTabs",
  "query": {
    "pageLayoutId": "0190c42f-2d5a-7000-8000-000000000071"
  }
}

Then list widgets under each tab:

{
  "resource": "pageLayoutWidgets",
  "query": {
    "pageLayoutTabId": "0190c42f-2d5a-7000-8000-000000000072"
  }
}

Both parent queries are mandatory and UUID-validated. Retain ordered child IDs and the fields that the planned body can change.

Snapshot webhook registrations

List webhooks with no query object. The connector rejects any query key for this resource and recursively removes every result field named secret.

Record registration IDs, target ownership, event selection, enabled state, and provider fields exposed by the current metadata document. Do not infer the configured secret from the redacted result.

4. Define one metadata intent

Choose exactly one operation and resource:

Intent Capability Required connector input
Add one resource metadata.create resource, provider-validated object body
Change one resource metadata.update resource, resource UUID, provider-validated object body
Remove one resource metadata.delete resource, resource UUID

Write the complete Action input from the frozen provider body contract. Retain its canonical hash and the expected before and after values.

Approval evidence should include:

  • schema digest and resource body contract;
  • parent and child IDs;
  • current dependency snapshot;
  • expected UI, automation, routing, and event effects;
  • rollback or restoration procedure outside the connector;
  • target tenant, workspace, credential, and configuration revisions.

The connector provides no dependency analysis or metadata transaction. Split multiple resources into ordered, independently verifiable intents.

5. Submit one governed change

Reserve a stable Action ID and external-account-scoped key:

export CAPABILITY='cap:twenty:metadata.update'
export INPUT_FILE='metadata-update.json'
export ACTION_ID='act_twenty_metadata_update_001'
export IDEMPOTENCY_KEY='twenty-metadata-update-v1'

Submit once:

aipctl \
  --native-bearer-token-file "$AIP_TOKEN_FILE" \
  action call "$AIP_URL" \
  "$CAPABILITY" \
  --action-id "$ACTION_ID" \
  --idempotency-key "$IDEMPOTENCY_KEY" \
  --mode sync \
  --input @"$INPUT_FILE"

Without admitted authorization, the Action enters requires_human. Approval must bind the exact resource, ID, body, schema and dependency evidence, policy hash, workspace, and intended effect.

Approval resumes the same queued Action. Do not replace the Action or key while the original remains pending.

All metadata mutations advertise unsafe retry. A key is required for ownership and collision control, not automatic replay.

6. Apply the webhook-secret rules

Skip this section for non-webhook resources.

Create a provider registration

The create input must use resource: webhooks. Its body must omit both secret and rotateConfiguredSecret.

The connector injects the secret configured by AIP_TWENTY_WEBHOOK_SECRET_FILE. Create fails when host webhook security is not configured.

The host exposes /webhooks/twenty only when the webhook secret is present. It also requires an authorized AIP_CONNECTOR_HOST_EVENT_ENDPOINT for central event delivery.

The provider target URL, public ingress, TLS, routing, and secret file must describe the same controlled deployment. Registration creation alone does not prove that ingress or publication works.

Rotate a provider registration

Use metadata.update for the exact webhook UUID. The body may include only this connector control when requesting host-secret injection:

{
  "resource": "webhooks",
  "id": "0190c42f-2d5a-7000-8000-000000000073",
  "body": {
    "rotateConfiguredSecret": true
  }
}

The connector removes rotateConfiguredSecret and injects the current host-owned secret. A caller-supplied secret, Boolean false, or another value is invalid.

Provider update and host secret rollout are not atomic. Use a deployment-owned cutover plan that defines old and new ingress ownership, validation, rollback, and the point at which the old secret is revoked.

Never place either secret value in Action input, approval evidence, logs, or a read-back comparison.

7. Read the durable mutation result

Read the original Action:

aipctl \
  --native-bearer-token-file "$AIP_TOKEN_FILE" \
  action status "$AIP_URL" \
  "$ACTION_ID" \
  --include-result \
  --include-receipts \
  --wait-ms 30000

Proceed only after terminal completed. Retain provider HTTP status, request ID, decoded redacted body, approval, and receipts.

For webhook metadata, every response field named secret is recursively removed. Absence of a secret in the result is expected and is not proof of a provider mismatch.

8. Verify the provider state

Use metadata.get on the validated result ID or the original update target. For a create whose result lacks a usable ID, perform a bounded parent-specific list and stop if the created resource cannot be uniquely identified.

Compare only reviewed fields from the frozen body contract. Re-list the affected parent children and confirm that unrelated IDs and ordering remain as expected.

For a delete, verify absence and re-read each known parent or dependent set. The connector does not state whether the provider cascades related resources.

For a webhook registration, also run a controlled signed delivery through the deployment ingress and verify durable AIP event publication. Metadata read-back alone does not exercise signature, replay, storage, or central delivery.

Recover without replaying a critical mutation

Observation Response
Action is requires_human Complete the original approval workflow
Action remains pending Read the same Action and receipts
Definitive provider rejection Refresh metadata schema and dependencies before a new intent
Temporary or transport failure Preserve Action and key; inspect provider metadata before another write
Invalid or oversized provider response Treat mutation outcome as uncertain and verify current state
Resource cannot be identified Stop; do not guess an ID or repeat create
Read-back differs Classify provider validation, automation, concurrency, or schema drift
Webhook metadata matches but delivery fails Preserve registration and inspect ingress, signature, replay, storage, and publication separately

The connector exposes no rollback or reconciliation operation. A recovery change is a new critical intent with current schema, dependency, approval, and idempotency evidence.

Retain the change evidence

Keep:

  • connector, artifact, provider mapping, tenant, workspace, and credential identities;
  • catalog revision and selected capability digests;
  • metadata OpenAPI digest and frozen body contract;
  • bounded before-state and dependency snapshot;
  • Action input hash, Action ID, key, approval, and policy hash;
  • terminal result, receipts, and provider request ID;
  • read-back and dependent-set comparison;
  • for webhooks, redacted registration and separate signed-delivery evidence;
  • recovery or rollback actions as independent chains.

This evidence supports one controlled metadata change. It does not establish general provider compatibility, atomic metadata migration, or qualification of another artifact or workspace.