Skip to main content

Data models

At-a-glance shape of the main objects. The API Reference generated from swagger-partner.json is the authoritative source — this page is the summary you can scan in one sitting.

Deal

{
"id": "uuid",
"product_name": "string",
"slug": "string",
"logo_url": "string",
"product_url": "string",
"short_description": "string",
"long_description": "string",
"perk_description": "string | null",
"market_value": "string",
"est_value": "number | null",
"categories": "<Category>[]",
"deal_type": "founderpass | partner_private",
"owner_partner_id": "uuid | null",
"tier": "free | premium",
"tags": "DealTag[]",
"badges": "string[]",
"redemption": "<Redemption> | null",
"eligibility_requirements": "string | null",
"eligibility_customer_type": "string[]",
"eligibility_company_stage": "string[]",
"eligibility_company_size": "string[]",
"eligibility_business_type": "string[]",
"eligibility_geography": "string[]",
"eligibility_incorporation": "string[]",
"eligibility_funding": "string[]",
"offer_types": "string[]",
"approval_required": false,
"approval_time": "string | null",
"status": "draft | live | expired | paused | coming_soon",
"start_date": "ISO 8601 date | null",
"end_date": "ISO 8601 date | null",
"active": true,
"hidden_globally": false,
"api_excluded": false,
"available_regions": "AudienceRegion[] (omitted = all regions; [] = no regions)",
"claimable_without_eligibility": "boolean (true = a default member can redeem with nothing extra supplied)",
"created_at": "ISO 8601",
"updated_at": "ISO 8601"
}

available_regions is the named-region allow-list where the deal is redeemable, derived from its region visibility rules. Three states: omitted = available in all regions; a non-empty list = redeemable only in those regions; an empty list [] = the region rules resolve to no regions (don't read [] as "all"). It is distinct from eligibility_geography (an eligibility dimension, ISO-3166 country codes) — see Listing deals.

claimable_without_eligibility is true when a default member (created with just an email) can redeem the deal right now with nothing extra supplied; false when they can't — blocked by a per-member gate (a targeted region, or a non-default eligibility dimension) or not redeemable yet (coming_soon). Partner-relative (region default = your account's regions) and excludes tier gating; user-type-only gates don't count (a default member has no user_types). Use it to hide un-claimable deals — see Listing deals.

See DealTag and DealStatus for valid enum values, and Listing deals for the eligibility-array vocabularies. api_excluded is a super_admin-managed flag that hides a deal from the Partner API channel while keeping it on the hosted app — see Visibility rules.

Partner-private deals created with POST /v1/partner-deals start as draft by default. Draft deals are returned by the partner-deal management endpoints, but they are not visible in GET /v1/deals until you publish them with PATCH /v1/partner-deals/{id} and status: "live".

Redemption

Embedded inside Deal.redemption. For the partner-specific instructions a member sees when they claim, hit GET /v1/deals/{id}/instructions?user_id={user_id} — same shape, but personalized.

{
"method": "url | promo_code | steps | form | unique_code | inquiry",
"instructions": "string (HTML)",
"promo_code": "string",
"redeem_url": "string",
"contact_email": "string"
}

User

What POST /v1/users returns and what GET /v1/users lists.

{
"id": "uuid",
"partner_id": "uuid",
"email": "string",
"external_user_id": "string | null",
"firebase_uid": "string | null",
"role": "super_admin | partner_admin | user",
"tier": "free | premium",
"user_types": "UserType[]",
"regions": "AudienceRegion[]",
"eligibility_customer_type": "string[]",
"eligibility_company_stage": "string[]",
"eligibility_company_size": "string[]",
"eligibility_business_type": "string[]",
"eligibility_geography": "string[]",
"eligibility_incorporation": "string[]",
"eligibility_funding": "string[]",
"created_at": "ISO 8601",
"updated_at": "ISO 8601"
}

The POST /v1/users response also includes sign_in_url (magic link) and already_exists (boolean) — see the Syncing users guide.

See UserType and AudienceRegion for valid enum values. The flat eligibility_* arrays mirror a deal's eligibility dimensions and gate which gated deals the user can see/redeem. They are set via a nested eligibility object on POST/PATCH /v1/users but returned flat (as above), using the same vocabularies as Listing deals → eligibility; only customer_type / company_size / incorporation resolve to permissive defaults when omitted.

VisibilityRule

{
"id": "uuid",
"deal_id": "uuid",
"rule_type": "include_partner | exclude_partner | include_partner_type | exclude_partner_type | include_region | exclude_region | include_user_type | exclude_user_type",
"rule_value": ["string"],
"priority": 0,
"created_at": "ISO 8601",
"updated_at": "ISO 8601"
}

See Visibility rules for what each rule_type controls and RuleType for the full enum.

Analytics summary

What GET /v1/analytics?days=N returns.

{
"total_users": 0,
"active_users": 0,
"total_deal_views": 0,
"total_redemptions": 0,
"upgrade_cta_clicks": 0,
"top_deals": [
{ "deal_id": "uuid", "product_name": "string", "views": 0, "redemptions": 0 }
],
"event_counts": {
"deal_list_viewed": 0,
"deal_detail_viewed": 0,
"deal_redeemed": 0
}
}