memμrondocs
Console
CONNECTORS

Google Drive

Sync Google Docs, Sheets, Slides, and PDFs from a user's Drive into a Memuron space. Files are parsed, chunked, embedded, and semantically linked exactly like uploads — and Memuron only ever sees the files the user hands over.

Quick setup

1. Create a connection

Pick the target space and where to send the user afterwards. The response carries the Google authorization link.

curl -X POST https://memuron-production.up.railway.app/memuron/connectors/google-drive \
  -H "Authorization: Bearer $MEMURON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "space_ref": "space.work",
    "redirect_url": "https://yourapp.com/connected",
    "document_limit": 3000
  }'
200 OK
{
  "id": "8f2c1a9e-…",
  "provider": "google-drive",
  "auth_link": "https://accounts.google.com/o/oauth2/v2/auth?…",
  "expires_in": "15 minutes",
  "redirects_to": "https://yourapp.com/connected"
}

2. Handle the OAuth callback

Redirect the user to auth_link. Google returns them to Memuron, which redirects on to your redirect_url with ?status=connected&connection=<id>. A user who declines arrives with ?status=error instead.

3. Let the user pick files

Authorizing is not enough on its own. Memuron holds the connection in pending_selection until the user chooses files in the Google Picker, and saving a non-empty selection activates the connection and queues the first sync.

# 1. Mint short-lived picker credentials
curl https://memuron-production.up.railway.app/memuron/connectors/$CONNECTION_ID/picker \
  -H "Authorization: Bearer $MEMURON_API_KEY"

# { "client_id": "…", "app_id": "…", "api_key": "…",
#   "oauth_token": "ya29.…",
#   "scopes": ["https://www.googleapis.com/auth/drive.file"] }

4. Check status

# List connections and their last sync run
curl https://memuron-production.up.railway.app/memuron/connectors \
  -H "Authorization: Bearer $MEMURON_API_KEY"

# List the documents that landed in the space
curl "https://memuron-production.up.railway.app/memuron/documents?space_ref=space.work" \
  -H "Authorization: Bearer $MEMURON_API_KEY"
200 OK
{
  "connections": [
    {
      "id": "8f2c1a9e-…",
      "provider": "google-drive",
      "status": "active",
      "account_email": "person@example.com",
      "space_token": "space.work",
      "selection_count": 2,
      "revisions_retained": 1,
      "item_counts": { "synced": 42, "remote_deleted": 1, "skipped": 2 },
      "last_sync": {
        "status": "completed",
        "started_at": "2026-08-03T09:14:00Z",
        "completed_at": "2026-08-03T09:15:22Z",
        "counts": {
          "ingest": 3, "reingest": 1, "unchanged": 38,
          "pending_deletions": 1, "queued": 4
        },
        "error_code": null
      }
    }
  ],
  "count": 1,
  "providers": ["google-drive"]
}

Sync scope

Memuron requests only the Google drive.file scope. That scope grants access to the specific items handed over through the Picker — Memuron cannot list, read, or index anything else in the account.

ModeBehaviour
selectedThe user picks files and folders. Picked folders are walked recursively; only those items sync.
Because access is granted per file, documents added to a picked folder afterthe picker ran are not included automatically. Re-run the picker — “Change selection” in the console — to widen the grant.

Supported document types

Google-native files are exported before parsing. Everything else is downloaded as-is and handled by the standard document parser.

TypeHandling
Google DocsExported to markdown
Google SheetsExported to .xlsx
Google SlidesExported to .pptx
PDF, DOCX, XLSX, PPTX, XLS, PPTDownloaded and parsed directly
CSV, TSV, JSON, YAML, HTML, XML, TXT, MDDownloaded and parsed directly
PNG, JPEG, WEBP, GIFParsed, with an optional vision pass describing the image
Conversion to markdown is lossy — some formatting is not preserved. Files over 8 MB, and types the parser does not support, are recorded as skipped with a reason. One bad file never fails the rest of a sync.

Syncing

Sync runs on demand: once when the selection is saved, and whenever you call the sync endpoint. Each call returns a job_id you poll like any other Memuron job. Internally one job enumerates Drive and queues a separate job per changed file, so a large first import makes progress incrementally and retries per file rather than all-or-nothing.

curl -X POST https://memuron-production.up.railway.app/memuron/connectors/$CONNECTION_ID/sync \
  -H "Authorization: Bearer $MEMURON_API_KEY"

# { "status": "queued", "connection_id": "…", "job_id": "…" }

# Poll like any other Memuron job
curl https://memuron-production.up.railway.app/memuron/jobs/$JOB_ID \
  -H "Authorization: Bearer $MEMURON_API_KEY"

Change detection is per file. Binary files compare Drive's content hash; Google-native files have no hash and fall back to modified time plus version. Unchanged files are never downloaded.

Syncing a connection that is still pending_selection returns 409. Finish the picker first.

Edited files keep their history

When a synced file changes, Memuron ingests a new document graph and retains the previous revision, linking the two with a supersedes edge and marking the older node state:superseded. Listings and search show one current document per Drive file; pass include_superseded=true to GET /memuron/documents to see the full chain.

Retained revisions still consume stored pages. Prune them when you want the quota back — the response reports exactly how much was reclaimed.
curl -X POST https://memuron-production.up.railway.app/memuron/connectors/$CONNECTION_ID/prune-revisions \
  -H "Authorization: Bearer $MEMURON_API_KEY"

# { "pruned_document_count": 4, "deleted_memory_count": 51,
#   "released_pages": 9 }

Deletions are always your decision

A sync never deletes anything. When a file disappears from Drive — moved to the trash, deleted, or unshared — the tracked item moves to remote_deleted and waits. The document stays searchable until you answer.

# 1. See what disappeared from Drive. Nothing has been removed.
curl "https://memuron-production.up.railway.app/memuron/connectors/$CONNECTION_ID/items?status=remote_deleted" \
  -H "Authorization: Bearer $MEMURON_API_KEY"

# 2. Answer. "keep" orphans the item so it is never raised again.
curl -X POST https://memuron-production.up.railway.app/memuron/connectors/$CONNECTION_ID/deletions \
  -H "Authorization: Bearer $MEMURON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "item_ids": ["…"], "decision": "delete" }'

# { "decision": "delete", "resolved_count": 1,
#   "deleted_memory_count": 12, "released_pages": 3 }
DecisionResult
keepThe document stays. The item is orphaned so it is never raised again.
deleteEvery revision of the document is purged and its stored pages are released.

Disconnecting

Deleting a connection revokes Memuron's Google authorization and stops all future syncs. Documents already imported are kept by default — pass delete_documents=true to purge them and reclaim their pages.

# Disconnect, keeping every document already imported (default)
curl -X DELETE https://memuron-production.up.railway.app/memuron/connectors/$CONNECTION_ID \
  -H "Authorization: Bearer $MEMURON_API_KEY"

# Disconnect and purge the documents, reclaiming their stored pages
curl -X DELETE "https://memuron-production.up.railway.app/memuron/connectors/$CONNECTION_ID?delete_documents=true" \
  -H "Authorization: Bearer $MEMURON_API_KEY"

Source identity

Every node a sync produces — the collection, the document, each chunk, and each placement — carries the Drive file id as source_id, a source_url linking back to the file, and a custom_id of google-drive:<file id>. Search results therefore cite back to the exact Drive file at any granularity.

Bring your own OAuth application

By default every organization authorizes against Memuron's shared Google application. On the Scale plan an organization can supply its own instead, so consent screens carry your branding and Drive access is governed by your Cloud project rather than ours.

Create a Web application OAuth client in your Google Cloud project, enable the Drive and Picker APIs, and register <memuron-api>/memuron/connectors/auth/callback/google-drive as an authorized redirect URI. The callback stays on Memuron even when the application is yours.

# Point this organization's connections at your own Google Cloud project
curl -X PUT https://memuron-production.up.railway.app/memuron/connector-settings/google-drive \
  -H "Authorization: Bearer $MEMURON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "…apps.googleusercontent.com",
    "client_secret": "…",
    "extras": { "app_id": "1234567890", "picker_api_key": "…" },
    "enabled": true
  }'

# Inspect what is configured. Secrets are never returned.
curl https://memuron-production.up.railway.app/memuron/connector-settings \
  -H "Authorization: Bearer $MEMURON_API_KEY"

# { "credentials": [{ "provider": "google-drive",
#   "client_id": "…", "has_client_secret": true,
#   "enabled": true, "in_use": true }], "count": 1 }

# Revert to Memuron's shared application
curl -X DELETE https://memuron-production.up.railway.app/memuron/connector-settings/google-drive \
  -H "Authorization: Bearer $MEMURON_API_KEY"
Client secrets are encrypted at rest and never returned by the API — the settings response only reports has_client_secret. Omit client_secret on a later update to keep the stored one while changing other fields.
Switching applications applies to new connections. Existing connections were authorized by the previous application, so Memuron marks them auth_expired and asks the user to reconnect rather than failing their next sync with an opaque Google error.

Status and error codes

CodeMeaning
pending_selectionAuthorized, but no files chosen yet. Sync is skipped until the picker is finished.
auth_expiredGoogle access was revoked or the refresh token died. The user must reconnect.
rate_limitedDrive quota exceeded. The job retries with backoff.
too_largeFile exceeds the 8 MB document limit; recorded as skipped.
provider_unavailableDrive was unreachable. The job retries automatically.