PlanetGraph Bulk Import Guide for Agents Version: 2026-07-31 Purpose Create or upsert large sets of Nodes, Edges, and Properties through asynchronous import jobs. Bulk imports use normal account ownership, authentication, billing, encryption, access policies, search rules, graph projection, and embeddings. Base URL and Authentication - API base: https://api.planetgraph.ai - OpenAPI: https://api.planetgraph.ai/openapi.json - Send X-API-Key: or Authorization: Bearer . - Never put credentials in a manifest, JSONL file, signed upload URL log, or error report. Choose a Submission Path 1) Inline JSON for manifests up to the configured inline limit, 1 MB by default. 2) Signed JSONL upload for larger files, 50 MB by default. Inline JSON Workflow POST /api/v1/imports Content-Type: application/json Example body: { "version": 1, "mode": "upsert", "idempotency_key": "crm-export-2026-07-31", "nodes": [ {"external_id": "person:123", "type": "Person", "visibility": "owner_only"}, {"external_id": "company:7", "type": "Company", "visibility": "public"} ], "edges": [ { "external_id": "employment:99", "type": "WORKS_AT", "source_external_id": "person:123", "source_type": "Person", "target_external_id": "company:7", "target_type": "Company", "visibility": "owner_only" } ], "properties": [ { "external_id": "person:123:name", "resource_external_id": "person:123", "resource_type": "node", "resource_entity_type": "Person", "name": "name", "type": "string", "value": "Ada", "search_mode": "exact", "search_scope": "owner_only" } ] } The response is HTTP 202 and contains the import job id and status. Signed JSONL Workflow 1) Serialize the complete JSONL file and calculate its exact byte length. 2) POST /api/v1/imports/uploads with {"expected_bytes": }. 3) PUT the bytes to upload_url. Send every required_headers entry exactly, including Content-Type: application/x-ndjson and the signed Content-Length. Do not send the PlanetGraph API key to the storage URL. 4) POST /api/v1/imports/uploads/{upload_id}/finalize with: {"version": 1, "mode": "upsert", "idempotency_key": "crm-export-large-2026-07-31"} 5) Use the returned import job id for status and results. Each nonblank JSONL line is one item. Examples: {"kind":"node","external_id":"person:123","type":"Person","visibility":"owner_only"} {"kind":"edge","external_id":"employment:99","type":"WORKS_AT","source_external_id":"person:123","source_type":"Person","target_external_id":"company:7","target_type":"Company","visibility":"owner_only"} {"kind":"property","external_id":"person:123:name","resource_external_id":"person:123","resource_type":"node","resource_entity_type":"Person","name":"name","type":"string","value":"Ada"} Identity and Idempotency - version must be 1. - mode is create_only or upsert. - Reuse the same idempotency_key only when retrying the same logical job. The same account and key return the existing job. - Node and Edge external_id values are stable identities scoped by account, resource kind, and entity type. - Include source system names in IDs when useful, for example salesforce:person:123. - Property external_id correlates results; canonical Property identity is resource plus Property name. - upsert reuses Node and Edge identities and replaces same-owner canonical Properties with history. - create_only reports existing identities as row errors. - Edge endpoint changes conflict for an existing Edge identity. Status, Results, and Control - GET /api/v1/imports/{import_id} - GET /api/v1/imports/{import_id}/results?limit=1000&offset=0 - GET /api/v1/imports/{import_id}/errors?limit=1000&offset=0 - POST /api/v1/imports/{import_id}/cancel - POST /api/v1/imports/{import_id}/retry Poll status with bounded backoff until completed, completed_with_errors, failed, or cancelled. Page results and errors until a page contains fewer records than the requested limit. Results contain item indexes, external IDs, status, resource IDs, attempts, and redacted diagnostics; they do not return Property values or staged payloads. Retry Behavior - retry requeues only retryable dependency, billing, transient database, and projection-enqueue failures below the attempt limit. - Correct nonretryable rows and submit a new job with a new idempotency_key. - A completed_with_errors job may still contain many successful writes; inspect results before resubmitting. Default Limits - 1 active job per account - 1 MB inline JSON - 50 MB uploaded JSONL - 100,000 Nodes - 250,000 Edges - 500,000 Properties - Results and errors page size: maximum 1,000 Agent Safety Rules - Do not invent internal resource IDs, owners, account IDs, billing fields, or storage URIs. - Upload only to the server-provided signed URL and finalize only its returned upload_id. - Keep signed URLs private; they are temporary capabilities. - Use deterministic external IDs and retain the import id, idempotency key, and source-to-external-ID mapping. - Do not assume completion means graph projection and embeddings are caught up; inspect the pending and failed event counts in status.