Quickstart
From nothing to a row you fetched yourself, in about five minutes.
1. Make a key
In your app, open Settings → Connections and create a key. It carriesyour permissions, so anything you cannot see it cannot fetch. Copy it now: it is shown once.
An app lives under its suite's address, at its own path:
export DUVAPPS_TOKEN="dva_live_…"
export DUVAPPS_APP="https://acme.gtable.app/crm"2. Read something
curl "$DUVAPPS_APP/v1/tables/tbl_8fj3kq2wmv5d/records?limit=5" \
-H "Authorization: Bearer $DUVAPPS_TOKEN"Every response is wrapped the same way, whether it is one thing or many. A record is keyed by field id, because an id survives a rename; meta.fields says which name each id has today:
{
"data": [ { "id": "rec_…", "fld_3ns8wq5ke2pb": "Acme renewal", "fld_7qk2mv9xp4ht": 20500 } ],
"meta": { "nextCursor": "eyJ…", "hasMore": true, "fields": { "fld_3ns8wq5ke2pb": "Name", "fld_7qk2mv9xp4ht": "Amount" } }
}Find your table ids with GET $DUVAPPS_APP/v1/schema.
3. Write something
Send an Idempotency-Key on every write. If the request is retried (and in a CI job it will be), you get the first response back instead of a duplicate row.
curl -X POST "$DUVAPPS_APP/v1/tables/tbl_8fj3kq2wmv5d/records" \
-H "Authorization: Bearer $DUVAPPS_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"records":[{"Name":"New deal","Amount":1000}]}'A field's exact name is accepted in place of its id when you write.
4. Give it to an agent
claude mcp add acme https://acme.gtable.app/mcpThe tool list it receives is built from your permissions. A table you cannot read is not listed: not refused when called, absent.