Profiles

A profile represents one of your end customers. Your API key is bound to exactly one, so every endpoint here operates on that profile and no other. See Core concepts for the model.

Profiles are created in the dashboard, not through the API.

GET/api/v1/profilesList profiles

Returns the single profile your key is bound to. The array shape exists so the response does not change if key scoping is ever relaxed.

curl --fail-with-body "$ADELI_URL/api/v1/profiles" \
-H "Authorization: Bearer $ADELI_API_KEY"
json
{
  "profiles": [
    {
      "id": "00000000-0000-4000-8000-000000000001",
      "name": "Client A",
      "externalId": "customer-123",
      "metadata": {},
      "isDefault": true,
      "createdAt": "2026-09-08T20:00:00.000Z",
      "updatedAt": "2026-09-08T20:00:00.000Z"
    }
  ]
}

Errors — 401 unauthorized, 404 profile_not_found, 502 database_error.

POST/api/v1/profilesCreate a profile — not available

Always returns 403 profile_scope_violation. A profile-scoped key cannot create another profile; if it could, one leaked key would let an attacker grow its own blast radius. Create profiles in the dashboard and issue a key per profile.

json
{
  "error": {
    "code": "profile_scope_violation",
    "message": "This API key is scoped to one profile and cannot create another profile"
  }
}

GET/api/v1/profiles/{profileId}Get a profile

Returns the profile as a bare object — not wrapped in profiles.

Path parameters

profileIduuidRequired
Must be the profile your key is bound to. Any other value returns 404 profile_not_found.

Errors — 401 unauthorized, 400 invalid_request, 404 profile_not_found, 502 database_error.

PUT/api/v1/profiles/{profileId}Update a profile

Replaces the mutable fields. This is a full replace, not a merge: omitting externalId or metadata clears them.

Body

namestringRequired
1–200 characters after trimming. Must be unique across your profiles.
externalIdstring | null
Up to 200 characters. Must be unique across your profiles when not null.
metadataobject | null
Any JSON object, up to 16 KiB encoded as UTF-8. Arrays and scalars are rejected.
curl --fail-with-body -X PUT \
"$ADELI_URL/api/v1/profiles/$PROFILE_ID" \
-H "Authorization: Bearer $ADELI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Client A","externalId":"customer-123","metadata":{"plan":"pro"}}'

Errors — 401 unauthorized, 400 invalid_request, 400 invalid_profile, 404 profile_not_found, 409 profile_name_conflict, 409 profile_external_id_conflict, 502 database_error.

Both conflict responses carry the colliding profile in details:

json
{
  "error": {
    "code": "profile_name_conflict",
    "message": "A profile with this name already exists",
    "details": { "existingProfileId": "00000000-0000-4000-8000-000000000009" }
  }
}

DELETE/api/v1/profiles/{profileId}Delete a profile

This cascades and cannot be undone

Deleting a profile removes its connected accounts, their cached history, its connection sessions, and its API keys — including, most likely, the key making this request. It does not delete anything on Instagram, Facebook, TikTok, or YouTube.

json
{ "id": "00000000-0000-4000-8000-000000000001", "deleted": true }

Errors — 401 unauthorized, 400 invalid_request, 404 profile_not_found, 502 database_error.