Skip to main content
v1

API Reference

The DAMdaryl API lets you search your asset library, analyze social posts, and get brand-aware asset recommendations — programmatically.

Authentication

The v1 API uses two authentication methods depending on the endpoint:

🔑 API keyAPI Key

For search, assets, and brands endpoints. Pass your API key as a Bearer token.

Authorization: Bearer dd_sk_your_api_key

API keys begin with dd_sk_

🔐 SessionSession Auth

For Post Intelligence, Brand Context, and pairings endpoints. Use a Supabase session JWT or let cookies authenticate automatically.

Authorization: Bearer <supabase_jwt>

In-browser requests authenticate via Supabase session cookie automatically.

Base URL & Versioning

All endpoints are versioned under /api/v1.

https://app.damdaryl.ai/api/v1

All requests and responses use JSON, except for the Recommend Assets endpoint which streams Server-Sent Events.

Errors

Errors return a JSON body with an error field describing what went wrong.

StatusMeaning
400Bad request — missing or invalid field
401Unauthorized — missing or invalid credentials
403Forbidden — valid credentials but no access to this resource
404Not found
500Server error — safe to retry
{ "error": "Missing required field: query" }

List Brands

🔑 API key

Returns all brands your API key has access to, along with their analyzed asset counts.

GET/api/v1/brands

Response

{
  "brands": [
    {
      "id": "brand_abc123",
      "name": "Acme Co",
      "industry": "consumer_goods",
      "logoUrl": "https://...",
      "assetCount": 1204
    }
  ]
}

Get Asset

🔑 API key

Returns full metadata for a single asset, including AI analysis, brand intelligence, and platform fit scores. Suitability scores are modeled estimates, not measured campaign performance.

GET/api/v1/assets/{assetId}

Path parameters

ParameterTypeDescription
assetIdstringrequiredThe asset ID returned from search results.

Response

{
  "asset": {
    "id": "asset_xyz789",
    "brandId": "brand_abc123",
    "fileName": "summer-campaign-01.jpg",
    "fileUrl": "https://...",
    "thumbnailUrl": "https://...",
    "fileType": "image/jpeg",
    "status": "analyzed",
    "createdAt": "2026-01-15T10:23:00Z",
    "analyzedAt": "2026-01-15T10:23:45Z",
    "width": 3000,
    "height": 2000,
    "fileSizeBytes": 2457600,

    "oneLiner": "Warm morning light filtering through linen curtains",
    "altText": "Person reading by a sunlit window",

    "hasProduct": false,
    "hasPeople": true,
    "hasText": false,
    "peopleCount": 1,

    "mood": "calm",
    "energy": "low",
    "productionStyle": "lifestyle",
    "contentType": "editorial",
    "setting": "interior",
    "season": "summer",

    "brandArchetype": "Caregiver",
    "brandPersonality": { "sincerity": 0.9, "excitement": 0.2, ... },
    "audienceArchetypes": ["The Explorer", "The Everyman"],
    "aspirationTension": "connection_vs_independence",
    "emotionalRegister": "tender",

    "platformScores": { "instagram": 0.91, "pinterest": 0.85, "linkedin": 0.34 },
    "platformNativeFit": "instagram",
    "postTypeFit": ["organic_lifestyle", "story"],
    "contentPillarFit": ["brand_story", "product_in_life"],
    "funnelStageFit": "awareness",

    "qualityScore": 0.87,
    "scrollStopScore": 0.74,
    "authenticityScore": 0.92,

    "aestheticTags": ["soft", "warm", "airy"],
    "aestheticEra": "contemporary",
    "colorTemperature": "warm",
    "dominantColors": ["#F5DEB3", "#D2B48C"],

    "copySuggestion": "Some mornings are worth savoring.",
    "captionToneCompatibility": "tender_and_aspirational",

    "hasV5Analysis": true
  }
}

Fields under brand intelligence, platform fit, and aesthetic are only populated when hasV5Analysis is true.

Get Download URL

🔑 API key

Returns a download URL for the original or thumbnail variant of an asset. Use this endpoint instead of storing raw file URLs — the URL format may change when signed URLs are introduced.

GET/api/v1/assets/{assetId}/download-url

Query parameters

ParameterTypeDescription
variant"original" | "thumbnail"optionalWhich variant to fetch. Defaults to "original".

Response

{
  "url": "https://...",
  "fileName": "summer-campaign-01.jpg",
  "contentType": "image/jpeg",
  "variant": "original",
  "expiresAt": null
}

expiresAt is currently null. URLs are public and do not expire today, but this field will be populated when signed URLs with expiration are introduced.

Analyze Post

🔐 Session

Analyzes a social media post to extract intent, tone, emotional register, and visual requirements. The resulting PostAnalysis object is required input for Recommend Assets.

POST/api/v1/post-intelligence/analyze

Request body

FieldTypeDescription
postTextstringrequiredThe social media post copy to analyze.
brandIdstringrequiredThe Brand Context for the analysis. Enables brand-aware scoring when generated context exists.
platformContextstringoptionalTarget platform (e.g. "instagram", "linkedin"). Improves platform-specific scoring.

Example request

POST /api/v1/post-intelligence/analyze
Authorization: Bearer <supabase_jwt>
Content-Type: application/json

{
  "postText": "Some mornings are worth savoring. ☕",
  "brandId": "brand_abc123",
  "platformContext": "instagram"
}

Response

{
  "primary_intent": "brand_awareness",
  "emotional_register": "tender",
  "tonal_register": ["warm", "aspirational"],
  "visual_implication": "soft morning light, cozy interior, slow moment",
  "brand_archetype": "Caregiver",
  "target_audience_archetypes": ["The Everyman", "The Explorer"],
  "platform_context": "instagram",
  "post_type": "organic_lifestyle"
}

Recommend Assets

🔐 Session

Runs the full recommendation pipeline against your asset library and streams results as Server-Sent Events. Requires the original user-written text in postAnalysis.raw_post_text. Derived fields cannot replace the brief. A generated lens profile is not required.

POST/api/v1/post-intelligence/recommend
Streaming response. This endpoint returns text/event-stream (SSE), not JSON. Each event is a JSON object prefixed with data: .

Request body

FieldTypeDescription
postAnalysisPostAnalysisrequiredAnalysis containing the complete original wording in raw_post_text. Image choice uses that original text.
brandIdstringrequiredBrand to search within; caller access and plan limits are checked.

SSE stream events

Progress events are emitted throughout the pipeline. Each is a data: {...} line.

// Progress events from the shared selector
data: {"step":"context","status":"in-progress","message":"Loading brand context..."}
data: {"step":"analyzing","status":"in-progress","message":"Understanding your query..."}
data: {"step":"daryl","status":"in-progress","message":"Curating recommendations..."}

// Final event — one of:
data: {"type":"results","matchState":"consider","recommendations":[...]}
data: {"type":"no-match","gapDiagnosis":"...","closest":[]}
data: {"type":"error","message":"Asset selection could not finish. Please try again."}}

Recommendation object

{
  "assetId": "asset_xyz789",
  "fileName": "summer-campaign-01.jpg",
  "thumbnailUrl": "https://...",
  "rationale": "Two empty chairs face the ocean.",
  "selectionMethod": "brief_fit",
  "evidence": "related",
  "unconfirmed": ["exact product identity"],
  "unconfirmedExclusions": [],
  "lensScores": null,
  "lensMatchQuality": null,
  "compositeScore": null
}}

New recommendations use the shared brief comparison. Legacy numeric lens fields are null when unmeasured. A completed empty choice is separate from a provider error; preserve every image’s evidence and restriction warnings.

Get Brand Context

🔐 Session

Returns the generated profile data that powers Brand Context. The API keeps the existing profile field for compatibility. It returns profile: null with coldStart: true when Brand Context has not yet been generated.

GET/api/v1/brand/{brandId}/profile

Response — profile exists

{
  "profile": {
    "brand_id": "brand_abc123",
    "primary_archetype": "Caregiver",
    "secondary_archetype": "Creator",
    "brand_personality": {
      "sincerity": 0.85,
      "excitement": 0.3,
      "competence": 0.6,
      "sophistication": 0.45,
      "ruggedness": 0.1
    },
    "content_pillars": ["brand_story", "product_in_life", "community"],
    "audience_archetypes": ["The Everyman", "The Explorer"],
    "platform_focus": ["instagram", "pinterest"],
    "production_style_preference": "lifestyle",
    "brand_profile_generated_at": "2026-03-01T12:00:00Z",
    "brand_profile_version": 2
  }
}

Response — cold start (profile not yet generated)

{ "profile": null, "coldStart": true }

Generate Brand Context

🔐 Session

Triggers background analysis of the brand's analyzed assets to generate the profile data used by Brand Context. Returns immediately — poll Get Brand Context until coldStart is false.

POST/api/v1/brand/{brandId}/profile/generate

Response

{ "status": "triggered", "brandId": "brand_abc123" }

Save Pairing

🔐 Session

Saves a confirmed post → asset pairing to your history. Use this after a user accepts a recommendation so it can be referenced and analyzed later.

POST/api/v1/pairings

Request body

FieldTypeDescription
brandIdstringrequiredBrand this pairing belongs to.
postTextstringrequiredThe post copy.
assetIdstringrequiredThe chosen asset ID.
rationalestringrequiredWhy this asset was chosen (from the recommendation).
lensScoresobject | nullrequiredHistorical lens scores, or null when no numeric assessment was made.
compositeScorenumber | nullrequiredHistorical numeric fit score (0–1), or null when unmeasured.
postAnalysisPostAnalysisrequiredThe full PostAnalysis object from Analyze Post.
platformstringoptionalTarget platform for the post.
assetFileNamestringoptionalAsset file name for display purposes.
assetThumbnailUrlstringoptionalThumbnail URL for display purposes.

Response

{ "id": "pairing_abc", "created_at": "2026-03-29T14:22:00Z" }

List Pairings

🔐 Session

Returns the 50 most recent post → asset pairings for a brand, ordered newest first.

GET/api/v1/pairings?brandId={brandId}

Query parameters

ParameterTypeDescription
brandIdstringrequiredFilter pairings by brand.

Response

{
  "pairings": [
    {
      "id": "pairing_abc",
      "brand_id": "brand_abc123",
      "post_text": "Some mornings are worth savoring. ☕",
      "platform": "instagram",
      "asset_id": "asset_xyz789",
      "asset_file_name": "summer-campaign-01.jpg",
      "asset_thumbnail_url": "https://...",
      "rationale": "Strong mood alignment...",
      "lens_scores": { "brand": 0.88, "audience": 0.79, "mood": 0.95, "platform": 0.84 },
      "composite_score": 0.87,
      "post_analysis": { ... },
      "created_at": "2026-03-29T14:22:00Z"
    }
  ]
}