API Documentation

Collective Memory Partner Ingest API

Version: v1

Audience: Partner apps integrating with Collective Memory ingestion

Public endpoint: https://api.collectivememory.ai/v1/memories/ingest

Quick Links

Overview

This API ingests image and video memories from partner applications into Collective Memory. It supports upsert behavior by memory ID, accepts low and high variants as separate calls, stores normalized media URLs, and enriches records with metadata such as tags and geolocation.

  • Create or update (upsert) by memory ID.
  • Low and high variants are sent as separate requests.
  • Partner media URLs are downloaded, stored, and normalized in memory records.
  • Videos store streaming-compatible playback URLs.
  • AI tags are generated for low variant only when tags do not already exist.

Authentication

Provide one of the following headers:

  • x-partner-key: <key>
  • x-api-key: <key>

Fallback is also supported via JSON body field partnerKey. If the key is invalid or missing, the API responds with 401 INVALID_PARTNER_KEY.

HTTP Request

Method: POST

Path: /v1/memories/ingest

Headers: Content-Type: application/json, plus auth header

Request Body Schema

{
  "partnerKey": "optional-if-header-sent",
  "memory": {
    "memoryId": "string, required",
    "mediaType": "image | video, required",
    "captureTimeUtc": "ISO8601 string, required",
    "deviceId": "string, required",
    "source": "string, required",
    "variant": {
      "type": "low | high, required",
      "url": "string URL, required",
      "bytes": 12345
    },
    "hashes": {
      "high": "string|null, optional",
      "low": "string|null, optional"
    },
    "location": {
      "lat": 45.123,
      "lng": 9.123,
      "accuracy": 8.5,
      "city": "optional",
      "country": "optional"
    }
  },
  "user": {
    "deviceId": "string, required",
    "creatorName": "string, required",
    "uid": "string|null, optional",
    "email": "string|null, optional",
    "walletAddress": "string|null, optional",
    "creditLink": "string|null, optional"
  }
}

Processing Rules

1) User resolution

Resolution order is user.email, then user.deviceId, otherwise a new user is created. The resolved user is used as creatorId and userId on the memory.

2) Memory ID handling

The API uses memory.memoryId as the primary ID. If there is a conflict with a non-partner memory, it falls back to format cm-pro:<memoryId>.

3) Media handling

The API downloads memory.variant.url and stores media with low and high variant paths. Final normalized URLs are written to memory fields.

4) Video URL contract

For videos, gcsUrl stores storage URL and imageUrl stores HLS playback URL. When high variant exists, subsequent low updates do not overwrite high video URLs.

5) Tags behavior

Tags are generated only when variant is low and tags are missing. If tags exist, no regeneration occurs. If AI fails, fallback tags may be used.

6) Geocoding

If location.city or location.country is missing and coordinates are present, reverse geocoding fills missing fields.

Success Responses

201 Created for a new memory:

{
  "status": "ok",
  "memoryId": "abc123",
  "variant": "low",
  "action": "created",
  "requestId": "uuid"
}

200 OK for updating an existing memory:

{
  "status": "ok",
  "memoryId": "abc123",
  "variant": "high",
  "action": "updated",
  "requestId": "uuid"
}

Error Responses

Standard error shape:

{
  "status": "error",
  "code": "ERROR_CODE",
  "message": "Human readable message"
}
  • METHOD_NOT_ALLOWED (405)
  • INVALID_PARTNER_KEY (401)
  • MISSING_FIELD (400)
  • INVALID_FIELD (400)
  • MEDIA_PROCESSING_FAILED (500)
  • INTERNAL (500)

Example Calls

A) Low variant (first call):

curl -X POST "https://api.collectivememory.ai/v1/memories/ingest" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_PARTNER_KEY" \
  -d '{
    "memory": {
      "memoryId": "partner-memory-001",
      "mediaType": "video",
      "captureTimeUtc": "2026-03-11T10:30:00.000Z",
      "deviceId": "device-123",
      "source": "procam",
      "variant": {
        "type": "low",
        "url": "https://partner-cdn.example.com/memory-001-low.mp4",
        "bytes": 48587
      },
      "location": {
        "lat": 45.82004,
        "lng": 9.23357,
        "accuracy": 8.57
      }
    },
    "user": {
      "deviceId": "device-123",
      "creatorName": "John Doe",
      "email": "john@example.com",
      "walletAddress": null,
      "creditLink": "https://partner.example.com/creator/john"
    }
  }'

B) High variant (second call, same memoryId):

curl -X POST "https://api.collectivememory.ai/v1/memories/ingest" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_PARTNER_KEY" \
  -d '{
    "memory": {
      "memoryId": "partner-memory-001",
      "mediaType": "video",
      "captureTimeUtc": "2026-03-11T10:30:00.000Z",
      "deviceId": "device-123",
      "source": "procam",
      "variant": {
        "type": "high",
        "url": "https://partner-cdn.example.com/memory-001-high.mp4",
        "bytes": 2866319
      }
    },
    "user": {
      "deviceId": "device-123",
      "creatorName": "John Doe",
      "email": "john@example.com"
    }
  }'

Integration Best Practices

  • Use the same memoryId for low and high variants of the same memory.
  • Recommended sequence is low variant first, then high variant.
  • Retries are safe because upsert behavior is supported.
  • Always send valid ISO8601 values for captureTimeUtc.
  • Include city/country if available to reduce geocoding dependency and latency.
  • Store partner keys on secure backend systems, never in client apps.

LLM-Friendly Quick Reference

The normalized JSON summary below is designed for AI agents and automation workflows.

{
  "api_name": "Collective Memory Partner Ingest API",
  "version": "v1",
  "method": "POST",
  "path": "/v1/memories/ingest",
  "auth_headers": ["x-partner-key", "x-api-key"],
  "auth_body_fallback": "partnerKey",
  "primary_key_field": "memory.memoryId",
  "variant_types": ["low", "high"],
  "media_types": ["image", "video"],
  "upsert_behavior": true,
  "success_statuses": [200, 201],
  "error_codes": {
    "405": "METHOD_NOT_ALLOWED",
    "401": "INVALID_PARTNER_KEY",
    "400": ["MISSING_FIELD", "INVALID_FIELD"],
    "500": ["MEDIA_PROCESSING_FAILED", "INTERNAL"]
  }
}