{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/instasent/json-schema/instasent-response-project-item-schema.json",
  "title": "ResponseProjectItem",
  "description": "Project entity",
  "x-generated": "2026-10-28",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/product.openapi.yaml#/components/schemas/ResponseProjectItem",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Project internal ID"
    },
    "uid": {
      "type": "string",
      "description": "Project UID (used in API paths)"
    },
    "name": {
      "type": "string",
      "description": "Project name"
    },
    "description": {
      "type": [
        "string",
        "null"
      ],
      "description": "Project description"
    },
    "projectType": {
      "type": "string",
      "description": "Type of project (e.g., 'standard')"
    },
    "projectStatus": {
      "type": "string",
      "description": "Project status (e.g., 'active')"
    },
    "locale": {
      "type": "string",
      "description": "Project locale (e.g., 'es_ES')"
    },
    "timezone": {
      "type": "string",
      "description": "Project timezone (e.g., 'Europe/Madrid')"
    },
    "defaultSmsSender": {
      "type": [
        "string",
        "null"
      ],
      "description": "ID of the default SMS sender"
    },
    "shortTrackingDomain": {
      "type": [
        "string",
        "null"
      ],
      "description": "ID of the project's own short-link tracking domain. null is the normal state and does not indicate a problem: the project then shortens links on a shared Instasent domain, and clicks are tracked identically. Configuring a domain of your own changes the branding of the link, not whether shortening or click tracking work."
    },
    "unsubscribeTrackingDomain": {
      "type": [
        "string",
        "null"
      ],
      "description": "ID of the project's own unsubscribe domain. null is the normal state and does not indicate a problem: the unsubscribe link is then served on a shared Instasent domain and opt-out works identically. Configuring a domain of your own changes the branding of the link only."
    },
    "generalConfig": {
      "type": "object",
      "description": "General project configuration with per-channel settings and cascade defaults",
      "additionalProperties": true,
      "properties": {
        "channelDefaults": {
          "$ref": "#/$defs/ChannelConfig",
          "description": "Default channel configuration (cascade terminal for all channels)"
        },
        "channelSms": {
          "$ref": "#/$defs/ChannelConfig",
          "nullable": true,
          "description": "SMS-specific channel configuration (overrides channelDefaults)"
        },
        "channelEmail": {
          "$ref": "#/$defs/ChannelConfig",
          "nullable": true,
          "description": "Email-specific channel configuration (overrides channelDefaults)"
        },
        "channelRcs": {
          "$ref": "#/$defs/ChannelConfig",
          "description": "RCS-specific channel configuration (overrides channelDefaults). RCS shares the SMS consent attributes but keeps its own default policy"
        },
        "channelWhatsapp": {
          "$ref": "#/$defs/ChannelConfig",
          "description": "WhatsApp-specific channel configuration (overrides channelDefaults)"
        }
      }
    },
    "attributionConfig": {
      "type": [
        "object",
        "null"
      ],
      "description": "Attribution tracking configuration (time windows for attribution)",
      "additionalProperties": true,
      "properties": {
        "hoursSmsCampaignSent": {
          "type": "integer",
          "description": "Hours window for SMS campaign attribution"
        },
        "hoursOtherCampaignSent": {
          "type": "integer",
          "description": "Hours window for other campaign attribution"
        },
        "hoursCampaignCta": {
          "type": "integer",
          "description": "Hours window for campaign CTA attribution"
        },
        "hoursCampaignOpen": {
          "type": "integer",
          "description": "Hours window for campaign open attribution"
        },
        "hoursFindOutboundSms": {
          "type": "integer",
          "description": "Hours window for outbound SMS attribution"
        }
      }
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "description": "When the project was created"
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "description": "When the project was last updated"
    }
  },
  "required": [
    "id",
    "uid",
    "name",
    "projectType",
    "projectStatus",
    "locale",
    "timezone",
    "createdAt",
    "updatedAt"
  ],
  "additionalProperties": true,
  "x-stoplight": {
    "id": "m5p46cm804ius"
  },
  "$defs": {
    "ChannelConfig": {
      "type": "object",
      "description": "Per-channel configuration. Values cascade from channel → channelDefaults → hardcoded constants.",
      "properties": {
        "defaultCompliancePolicy": {
          "type": "string",
          "enum": [
            "opt-in",
            "no-opt-out",
            "basic"
          ],
          "description": "The consent policy campaigns on this channel take when they do not name one. Always resolved in responses (channel, then `channelDefaults`, then `basic`), never null. Pass it as `filterCompliance` to `/audience/count` to know how many contacts a campaign under the project's policy reaches.\n"
        },
        "optInKeywords": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string"
          },
          "description": "Keywords that trigger opt-in"
        },
        "optOutKeywords": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string"
          },
          "description": "Keywords that trigger opt-out"
        },
        "autoMarketingOptInOnInbound": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Whether to auto-set accepts_marketing=true on inbound messages"
        },
        "autoCreateContactsOnInbounds": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Whether to automatically create contacts on inbound messages"
        },
        "autoCreateContactsOnOutbounds": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Whether to automatically create contacts on outbound messages"
        },
        "marketingOptOutScope": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "per_channel",
            "global"
          ],
          "description": "Scope of marketing opt-out (per_channel or global across all channels)"
        },
        "marketingOptInScope": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "per_channel",
            "global"
          ],
          "description": "Scope of marketing opt-in (per_channel or global across all channels)"
        }
      }
    }
  }
}