Skip to content
Niftyhelp 2026.10.1-beta.1 Support

Beta This is the help for Nifty 2026.10.1-beta.1, which isn't released yet. Help for the current release

People

The people you know, with their key dates, contact details and positions.

On this page

List people

GET/people

People, with their key dates and contact details.

curl "$NIFTY_URL/api/v1/people" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Query parameters

NameDescription
ordername | created_at | updated_at | id · optionalThe field to sort by; ties are broken by id, so the order is stable.
directionasc | desc · optionalasc (ascending) or desc (descending), for order.
relationshipRelationshipKeyInput or family · optionalOnly people with this relationship to the owner, or any family one (family). Anything else is 400.
updated_sincedate-time · optionalOnly records updated at or after this time (ISO 8601 with Z or a UTC offset), ordered by updated_at, id.
cursorstring · optionalmeta.next_cursor from the previous page.
limitinteger · optionalItems per page, up to 100; a larger number is taken as 100.
counttrue | false · optionaltrue adds meta.total_count: the size of the filtered set (with updated_since too), ignoring cursor and limit. Anything but true or false is a 400.

Response

200 OK Errors: 400 401 429

{
  "data": [
    {
      "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "name": "Maya Okafor",
      "avatar": {
        "url": "https://example.com",
        "thumb_url": "https://example.com",
        "large_url": "https://example.com"
      },
      "key_dates": [
        {
          "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "kind": "birthday",
          "label": "Graduation",
          "day": 1,
          "month": 1,
          "year": 1,
          "created_at": "2026-10-10T09:30:00Z",
          "updated_at": "2026-10-10T09:30:00Z"
        }
      ],
      "email_addresses": [
        {
          "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "address": "[email protected]",
          "label": "Work",
          "created_at": "2026-10-10T09:30:00Z",
          "updated_at": "2026-10-10T09:30:00Z"
        }
      ],
      "phone_numbers": [
        {
          "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "number": "+44 20 7946 0958",
          "label": "Mobile",
          "created_at": "2026-10-10T09:30:00Z",
          "updated_at": "2026-10-10T09:30:00Z"
        }
      ],
      "social_profiles": [
        {
          "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "url": "https://example.com",
          "platform": "website",
          "platform_detected": true,
          "label": "Blog",
          "created_at": "2026-10-10T09:30:00Z",
          "updated_at": "2026-10-10T09:30:00Z"
        }
      ],
      "positions": [
        {
          "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "title": "Head of Design",
          "company_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "created_at": "2026-10-10T09:30:00Z",
          "updated_at": "2026-10-10T09:30:00Z"
        }
      ],
      "relationships": [
        "spouse"
      ],
      "connections": [
        {
          "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "kind": "spouse",
          "note": "Met at university"
        }
      ],
      "created_at": "2026-10-10T09:30:00Z",
      "updated_at": "2026-10-10T09:30:00Z"
    }
  ],
  "meta": {
    "next_cursor": "eyJrIjpbIjIwMjYtMTAtMDlUMDg6MzA6MDBaIl19",
    "limit": 1,
    "total_count": 1
  }
}

Add a person

POST/people

Add a person, with any key dates, contact details and positions.

curl -X POST "$NIFTY_URL/api/v1/people" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"person":{"name":"Alice Hart","relationships":["friend"],"key_dates":[{"kind":"birthday","day":14,"month":3,"year":1988}],"email_addresses":[{"address":"[email protected]","label":"home"}],"positions":[{"title":"Head of Design","company_name":"Northwind"}]}}'

Headers

NameDescription
Idempotency-Keystring · optionalMakes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth).

Request body

NameDescription
personPersonFieldsA person's writable fields (PersonInput). Each array follows the rules on PATCH. A social profile's platform equal to the one currently detected for it is no change, so a GET sent back as a PATCH keeps it detected.
person.namestring · optional
person.avatarstring or null · optionalThe photo, saved with the rest: an upload's signed_id from POST /uploads, or null to remove it. Omitted keeps it. Only an upload nothing uses yet is accepted; any other signed id (e.g. a note's image, or an unknown one) is a 422 on avatar, "isn’t a new upload". The photo rules apply (a JPEG, PNG, WebP or GIF of 10 MB or less). Anything but a string or null is a 400. A replaced or removed photo is deleted.
person.relationshipsRelationshipKeyInput[] · optionalThe whole set of relationships to the owner. Omitted keeps them; [] clears them. An unknown key is a 422.
person.key_datesobject[] · optionalA new row needs kind, day and month; the year is optional (1900 to this year, not in the future). label is required for other. A new row with no day, month, year or label is ignored. At most one birthday: to make another existing row the birthday, change the old birthday to another kind in an earlier request (in one request it can be refused, depending on the rows' order).
person.key_dates[].idULID · optionalA record's ID.
person.key_dates[].kindKeyDateKind · optional
person.key_dates[].labelstring or null · optional
person.key_dates[].dayWholeNumberInput · optionalA whole number, or one written as a string ("5"); null or "" is none.
person.key_dates[].monthWholeNumberInput · optionalA whole number, or one written as a string ("5"); null or "" is none.
person.key_dates[].yearWholeNumberInput · optionalA whole number, or one written as a string ("5"); null or "" is none.
person.key_dates[]._destroyboolean · optional
person.email_addressesobject[] · optional
person.email_addresses[].idULID · optionalA record's ID.
person.email_addresses[].addressstring · optional
person.email_addresses[].labelstring or null · optional
person.email_addresses[]._destroyboolean · optional
person.phone_numbersobject[] · optional
person.phone_numbers[].idULID · optionalA record's ID.
person.phone_numbers[].numberstring · optional
person.phone_numbers[].labelstring or null · optional
person.phone_numbers[]._destroyboolean · optional
person.social_profilesobject[] · optional
person.social_profiles[].idULID · optionalA record's ID.
person.social_profiles[].urlstring · optionalhttps:// is added when there's no scheme.
person.social_profiles[].platformwebsite | linkedin | instagram | facebook | x | bluesky | mastodon | threads | github | youtube | tiktok | other | null · optionalNull (or omitted) detects it from the link.
person.social_profiles[].labelstring or null · optional
person.social_profiles[]._destroyboolean · optional
person.positionsobject[] · optionalA row with id changes it, one without adds, _destroy removes. Each needs a title or a company (a new row with neither is a 422 on title). The company changes when company_id or company_name is sent: company_id names a /companies record (an unknown one is a 422), company_name finds a company ignoring case or adds it, and null or a blank name clears it. Sending both non-null is a 422 on company_name. A company no position names any more is deleted (it appears in /deletions). An id sent twice in one request is a 422 on the later row.
person.positions[].idULID · optionalA record's ID.
person.positions[].titlestring or null · optionalSpaces are squished; blank is null.
person.positions[].company_idULID or null · optionalA record's ID.
person.positions[].company_namestring or null · optionalSpaces are squished.
person.positions[]._destroyboolean · optional

Response

201 Created Errors: 400 401 403 409 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Maya Okafor",
    "avatar": {
      "url": "https://example.com",
      "thumb_url": "https://example.com",
      "large_url": "https://example.com"
    },
    "key_dates": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "birthday",
        "label": "Graduation",
        "day": 1,
        "month": 1,
        "year": 1,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "email_addresses": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "address": "[email protected]",
        "label": "Work",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "phone_numbers": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "number": "+44 20 7946 0958",
        "label": "Mobile",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "social_profiles": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "url": "https://example.com",
        "platform": "website",
        "platform_detected": true,
        "label": "Blog",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "positions": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "Head of Design",
        "company_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "relationships": [
      "spouse"
    ],
    "connections": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "spouse",
        "note": "Met at university"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Get a person

GET/people/{id}

curl "$NIFTY_URL/api/v1/people/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

200 OK Errors: 401 404 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Maya Okafor",
    "avatar": {
      "url": "https://example.com",
      "thumb_url": "https://example.com",
      "large_url": "https://example.com"
    },
    "key_dates": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "birthday",
        "label": "Graduation",
        "day": 1,
        "month": 1,
        "year": 1,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "email_addresses": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "address": "[email protected]",
        "label": "Work",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "phone_numbers": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "number": "+44 20 7946 0958",
        "label": "Mobile",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "social_profiles": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "url": "https://example.com",
        "platform": "website",
        "platform_detected": true,
        "label": "Blog",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "positions": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "Head of Design",
        "company_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "relationships": [
      "spouse"
    ],
    "connections": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "spouse",
        "note": "Met at university"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Change a person

PATCH/people/{id}

Also PUT /people/{id}, the same.

Change a person, their key dates, contact details and positions.

Only the fields sent change. In each key-date, contact-detail and position array, a row with an id updates that row, one without adds a row, and "_destroy": true removes one; rows not sent are kept. An id that isn't this person's is a 422 on that row (removing one that's already gone is fine). avatar sets or removes the photo in the same save.

curl -X PATCH "$NIFTY_URL/api/v1/people/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"person":{"name":"Alice Hart","relationships":["friend"],"key_dates":[{"kind":"birthday","day":14,"month":3,"year":1988}],"email_addresses":[{"address":"[email protected]","label":"home"}],"positions":[{"title":"Head of Design","company_name":"Northwind"}]}}'

Path parameters

NameDescription
idULIDA record's ID.

Request body

NameDescription
personPersonFieldsA person's writable fields (PersonInput). Each array follows the rules on PATCH. A social profile's platform equal to the one currently detected for it is no change, so a GET sent back as a PATCH keeps it detected.
person.namestring · optional
person.avatarstring or null · optionalThe photo, saved with the rest: an upload's signed_id from POST /uploads, or null to remove it. Omitted keeps it. Only an upload nothing uses yet is accepted; any other signed id (e.g. a note's image, or an unknown one) is a 422 on avatar, "isn’t a new upload". The photo rules apply (a JPEG, PNG, WebP or GIF of 10 MB or less). Anything but a string or null is a 400. A replaced or removed photo is deleted.
person.relationshipsRelationshipKeyInput[] · optionalThe whole set of relationships to the owner. Omitted keeps them; [] clears them. An unknown key is a 422.
person.key_datesobject[] · optionalA new row needs kind, day and month; the year is optional (1900 to this year, not in the future). label is required for other. A new row with no day, month, year or label is ignored. At most one birthday: to make another existing row the birthday, change the old birthday to another kind in an earlier request (in one request it can be refused, depending on the rows' order).
person.key_dates[].idULID · optionalA record's ID.
person.key_dates[].kindKeyDateKind · optional
person.key_dates[].labelstring or null · optional
person.key_dates[].dayWholeNumberInput · optionalA whole number, or one written as a string ("5"); null or "" is none.
person.key_dates[].monthWholeNumberInput · optionalA whole number, or one written as a string ("5"); null or "" is none.
person.key_dates[].yearWholeNumberInput · optionalA whole number, or one written as a string ("5"); null or "" is none.
person.key_dates[]._destroyboolean · optional
person.email_addressesobject[] · optional
person.email_addresses[].idULID · optionalA record's ID.
person.email_addresses[].addressstring · optional
person.email_addresses[].labelstring or null · optional
person.email_addresses[]._destroyboolean · optional
person.phone_numbersobject[] · optional
person.phone_numbers[].idULID · optionalA record's ID.
person.phone_numbers[].numberstring · optional
person.phone_numbers[].labelstring or null · optional
person.phone_numbers[]._destroyboolean · optional
person.social_profilesobject[] · optional
person.social_profiles[].idULID · optionalA record's ID.
person.social_profiles[].urlstring · optionalhttps:// is added when there's no scheme.
person.social_profiles[].platformwebsite | linkedin | instagram | facebook | x | bluesky | mastodon | threads | github | youtube | tiktok | other | null · optionalNull (or omitted) detects it from the link.
person.social_profiles[].labelstring or null · optional
person.social_profiles[]._destroyboolean · optional
person.positionsobject[] · optionalA row with id changes it, one without adds, _destroy removes. Each needs a title or a company (a new row with neither is a 422 on title). The company changes when company_id or company_name is sent: company_id names a /companies record (an unknown one is a 422), company_name finds a company ignoring case or adds it, and null or a blank name clears it. Sending both non-null is a 422 on company_name. A company no position names any more is deleted (it appears in /deletions). An id sent twice in one request is a 422 on the later row.
person.positions[].idULID · optionalA record's ID.
person.positions[].titlestring or null · optionalSpaces are squished; blank is null.
person.positions[].company_idULID or null · optionalA record's ID.
person.positions[].company_namestring or null · optionalSpaces are squished.
person.positions[]._destroyboolean · optional

Response

200 OK Errors: 400 401 403 404 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Maya Okafor",
    "avatar": {
      "url": "https://example.com",
      "thumb_url": "https://example.com",
      "large_url": "https://example.com"
    },
    "key_dates": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "birthday",
        "label": "Graduation",
        "day": 1,
        "month": 1,
        "year": 1,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "email_addresses": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "address": "[email protected]",
        "label": "Work",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "phone_numbers": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "number": "+44 20 7946 0958",
        "label": "Mobile",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "social_profiles": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "url": "https://example.com",
        "platform": "website",
        "platform_detected": true,
        "label": "Blog",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "positions": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "Head of Design",
        "company_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "relationships": [
      "spouse"
    ],
    "connections": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "spouse",
        "note": "Met at university"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Delete a person

DELETE/people/{id}

Delete a person, their key dates, contact details, positions and links.

Restorable for 20 seconds (POST /people/{id}/restoration), then permanent. The person is gone from every endpoint at once, and deletion records are written for the person, each key date, contact detail and position, each person link (either side) whose other person isn't deleted too, and each project membership whose project isn't deleted. The other person in each link, their projects (members changes), and notes mentioning them get a new updated_at (notes drop them from person_ids). Once the 20 seconds have passed, each mention becomes plain text "@Name" and those notes get a new updated_at (but not edited_at). Deleting again is a 404.

curl -X DELETE "$NIFTY_URL/api/v1/people/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

204 Deleted Errors: 401 403 404 429

Restore a person

POST/people/{person_id}/restoration

Undo deleting a person.

Within 20 seconds of DELETE /people/{id}: brings the person back with everything they had (contact details, positions, links, project memberships, photo, mentions). Their deletion records are removed, and they, their links, the people they're linked to, their memberships and projects, and the notes mentioning them get a new updated_at. No body. Restoring someone who isn't deleted changes nothing and returns them, so a retry is safe. Once the 20 seconds have passed, or for an unknown id, it's a 404.

curl -X POST "$NIFTY_URL/api/v1/people/01j9zq3k8m5x2v7c4n6b0t1r9e/restoration" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
person_idULIDA record's ID.

Headers

NameDescription
Idempotency-Keystring · optionalMakes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth).

Response

200 Restored. The person, as GET /people/{id} returns them. Errors: 400 401 403 404 409 415 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Maya Okafor",
    "avatar": {
      "url": "https://example.com",
      "thumb_url": "https://example.com",
      "large_url": "https://example.com"
    },
    "key_dates": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "birthday",
        "label": "Graduation",
        "day": 1,
        "month": 1,
        "year": 1,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "email_addresses": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "address": "[email protected]",
        "label": "Work",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "phone_numbers": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "number": "+44 20 7946 0958",
        "label": "Mobile",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "social_profiles": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "url": "https://example.com",
        "platform": "website",
        "platform_detected": true,
        "label": "Blog",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "positions": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "Head of Design",
        "company_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "relationships": [
      "spouse"
    ],
    "connections": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "spouse",
        "note": "Met at university"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

List a person's meetings

GET/people/{person_id}/meetings

A person's upcoming meetings.

The calendar feeds' event occurrences the person attends (see CalendarAttendee for how attendees are matched), from now to 60 days from today in the owner's time zone: those not yet ended (an all-day one through its last day), soonest first, then all-day ones first, then title. Not paginated: limit bounds it, and meta.has_more says whether there are more in the 60 days. A view, not a record: nothing to sync.

curl "$NIFTY_URL/api/v1/people/01j9zq3k8m5x2v7c4n6b0t1r9e/meetings" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
person_idULIDA record's ID.

Query parameters

NameDescription
limitinteger · optionalAt most this many; otherwise 400.

Response

200 OK Errors: 400 401 404 429

{
  "data": [
    {
      "key": "string",
      "feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "title": "Team stand-up",
      "all_day": true,
      "starts_at": "2026-10-10T09:30:00Z",
      "ends_at": "2026-10-10T09:30:00Z",
      "start_on": "2026-10-10",
      "end_on": "2026-10-10",
      "location": "Room 2",
      "description": "Weekly check-in.",
      "url": "string",
      "meeting": {
        "provider": "google_meet",
        "url": "https://example.com"
      },
      "attendee_count": 0,
      "attendee_names": [
        "string"
      ],
      "attendees": [
        {
          "name": "Maya Okafor",
          "email": "[email protected]",
          "organizer": true,
          "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e"
        }
      ],
      "rrule": "FREQ=WEEKLY;BYDAY=MO,WE"
    }
  ],
  "meta": {
    "limit": 1,
    "has_more": true
  }
}

Set a person's photo

PUT/people/{person_id}/avatar

Also PATCH /people/{person_id}/avatar, the same.

The body is the image itself, up to 10 MB, with a Content-Length (without one it's 411 length_required). The type is read from the bytes; the Content-Type must still be one of the image types below (anything else is 415). Replaces any existing photo.

curl -X PUT "$NIFTY_URL/api/v1/people/01j9zq3k8m5x2v7c4n6b0t1r9e/avatar" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '"@file.pdf"'

Path parameters

NameDescription
person_idULIDA record's ID.

Response

200 OK Errors: 401 403 404 411 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Maya Okafor",
    "avatar": {
      "url": "https://example.com",
      "thumb_url": "https://example.com",
      "large_url": "https://example.com"
    },
    "key_dates": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "birthday",
        "label": "Graduation",
        "day": 1,
        "month": 1,
        "year": 1,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "email_addresses": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "address": "[email protected]",
        "label": "Work",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "phone_numbers": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "number": "+44 20 7946 0958",
        "label": "Mobile",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "social_profiles": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "url": "https://example.com",
        "platform": "website",
        "platform_detected": true,
        "label": "Blog",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "positions": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "Head of Design",
        "company_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "relationships": [
      "spouse"
    ],
    "connections": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "spouse",
        "note": "Met at university"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Remove a person's photo

DELETE/people/{person_id}/avatar

Succeeds when there's no photo too.

curl -X DELETE "$NIFTY_URL/api/v1/people/01j9zq3k8m5x2v7c4n6b0t1r9e/avatar" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
person_idULIDA record's ID.

Response

200 OK Errors: 401 403 404 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Maya Okafor",
    "avatar": {
      "url": "https://example.com",
      "thumb_url": "https://example.com",
      "large_url": "https://example.com"
    },
    "key_dates": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "birthday",
        "label": "Graduation",
        "day": 1,
        "month": 1,
        "year": 1,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "email_addresses": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "address": "[email protected]",
        "label": "Work",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "phone_numbers": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "number": "+44 20 7946 0958",
        "label": "Mobile",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "social_profiles": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "url": "https://example.com",
        "platform": "website",
        "platform_detected": true,
        "label": "Blog",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "positions": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "Head of Design",
        "company_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    ],
    "relationships": [
      "spouse"
    ],
    "connections": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "spouse",
        "note": "Met at university"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

List upcoming key dates

GET/upcoming_key_dates

Key dates (birthdays, anniversaries…) that fall from today to days from today, inclusive, in the owner's time zone, ordered by date, then person name, then kind. Not paginated (days bounds it). 29 February falls on 1 March in non-leap years.

curl "$NIFTY_URL/api/v1/upcoming_key_dates" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Query parameters

NameDescription
daysinteger · optional
kindstring · optionalComma-separated kinds, e.g. birthday,anniversary. Omitted gives every kind.

Response

200 OK Errors: 400 401 429

{
  "data": [
    {
      "date": "2026-10-10",
      "years": 1,
      "key_date": {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "birthday",
        "label": "Graduation",
        "day": 1,
        "month": 1,
        "year": 1,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      },
      "person": {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "name": "Maya Okafor",
        "avatar": {
          "url": "https://example.com",
          "thumb_url": "https://example.com",
          "large_url": "https://example.com"
        },
        "relationships": [
          "spouse"
        ]
      }
    }
  ]
}

List relationship and key date types

GET/relationship_types

The relationship, key date and social platform types, with labels.

Deprecated, use GET /vocabulary, which has these four lists too. Not paginated. Relationship and person link labels are lower case, read as "Ada is your <label>" and "Alice is Bob's <label>"; key date kind and platform labels are as the web UI shows them ("Work anniversary", "LinkedIn").

curl "$NIFTY_URL/api/v1/relationship_types" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Response

200 OK Errors: 401 429

{
  "data": {
    "relationships": [
      {
        "key": "spouse",
        "label": "direct report",
        "group": "family"
      }
    ],
    "person_links": [
      {
        "key": "spouse",
        "label": "parent",
        "group": "family",
        "inverse_key": "spouse",
        "inverse_label": "child",
        "symmetric": true,
        "synonyms": [
          "mother",
          "father",
          "mum",
          "mom",
          "dad"
        ]
      }
    ],
    "key_date_kinds": [
      {
        "key": "birthday",
        "label": "Work anniversary",
        "icon": "cake"
      }
    ],
    "social_platforms": [
      {
        "key": "website",
        "label": "LinkedIn"
      }
    ]
  }
}

Relationships

A person's relationships are how they relate to you, as keys from GET /vocabulary (the person link roles except introduced and introduced_by). Links between two people are /person_links. Every kind names the role of the person in the record's person_id: the link { person_id: A, kind: "parent", related_person_id: B } reads "A is B's parent".

Menu

2026.10.1-beta.1Contact support