{
  "openapi": "3.1.0",
  "info": {
    "title": "Goma API",
    "version": "1.0.0",
    "description": "Real-time people data in one call: a person's current profile, or who just joined a company. Credit-metered — each endpoint lists its price; failed calls are never charged.",
    "contact": { "name": "Goma", "url": "https://trygoma.com" }
  },
  "servers": [{ "url": "https://trygoma.com", "description": "Production" }],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/api/v1/person/profile": {
      "get": {
        "operationId": "getPersonProfile",
        "summary": "Look up a person's LinkedIn profile",
        "description": "Returns a normalized public profile for the given LinkedIn profile URL. Costs 1 credit on success; no credit is charged on any error.",
        "x-credit-cost": 1,
        "tags": ["Person"],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "A public LinkedIn profile URL, e.g. https://www.linkedin.com/in/satyanadella/",
            "schema": { "type": "string", "format": "uri" },
            "example": "https://www.linkedin.com/in/satyanadella/"
          }
        ],
        "responses": {
          "200": {
            "description": "Profile found and returned. 1 credit charged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Profile" },
                    "meta": { "$ref": "#/components/schemas/Meta" }
                  }
                },
                "example": {
                  "data": {
                    "public_identifier": "priya-raman-x9q7z",
                    "linkedin_url": "https://www.linkedin.com/in/priya-raman-x9q7z/",
                    "first_name": "Priya",
                    "last_name": "Raman",
                    "headline": "VP Finance at Okto | ex-Brightline",
                    "about": "Finance leader for high-growth B2B software companies.",
                    "location": { "text": "Austin, Texas, United States", "country": "United States", "country_code": "US", "state": "Texas", "city": "Austin" },
                    "premium": true,
                    "open_to_work": false,
                    "hiring": true,
                    "follower_count": 2140,
                    "connections_count": 1876,
                    "current_position": [
                      {
                        "title": "VP Finance",
                        "company_name": "Okto",
                        "company_linkedin_url": "https://www.linkedin.com/company/okto/",
                        "employment_type": "Full-time",
                        "location": "Austin, Texas, United States",
                        "description": null,
                        "start_date": "Aug 2026",
                        "end_date": "Present"
                      },
                      {
                        "title": "Board Advisor",
                        "company_name": "Fernway",
                        "company_linkedin_url": "https://www.linkedin.com/company/fernway/",
                        "employment_type": "Part-time",
                        "location": null,
                        "description": null,
                        "start_date": "Jan 2024",
                        "end_date": "Present"
                      }
                    ],
                    "experience": [
                      {
                        "title": "VP Finance",
                        "company_name": "Okto",
                        "company_linkedin_url": "https://www.linkedin.com/company/okto/",
                        "employment_type": "Full-time",
                        "location": "Austin, Texas, United States",
                        "description": null,
                        "start_date": "Aug 2026",
                        "end_date": "Present"
                      },
                      {
                        "title": "Board Advisor",
                        "company_name": "Fernway",
                        "company_linkedin_url": "https://www.linkedin.com/company/fernway/",
                        "employment_type": "Part-time",
                        "location": null,
                        "description": null,
                        "start_date": "Jan 2024",
                        "end_date": "Present"
                      },
                      {
                        "title": "Director of FP&A",
                        "company_name": "Brightline",
                        "company_linkedin_url": "https://www.linkedin.com/company/brightline/",
                        "employment_type": "Full-time",
                        "location": "Austin, Texas, United States",
                        "description": "Led planning and forecasting through Series B to C.",
                        "start_date": "Mar 2021",
                        "end_date": "Jul 2026"
                      }
                    ],
                    "education": [
                      { "school": "The University of Texas at Austin", "school_linkedin_url": "https://www.linkedin.com/school/the-university-of-texas-at-austin/", "degree": "BBA", "field_of_study": "Finance", "period": "2010 - 2014" }
                    ],
                    "skills": ["Financial Planning & Analysis", "SaaS Metrics", "Forecasting"],
                    "languages": ["English", "Tamil"],
                    "insights": {
                      "job_change": {
                        "type": "new_company",
                        "title": "VP Finance",
                        "company_name": "Okto",
                        "company_linkedin_url": "https://www.linkedin.com/company/okto/",
                        "start_month": "2026-08"
                      }
                    }
                  },
                  "meta": { "request_id": "3f6c2a1e-8b4d-4c7a-9e2f-1a5b6c7d8e9f", "credits_remaining": 9999 }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "402": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "429": {
            "description": "Rate limited. Retry after the interval in the Retry-After header.",
            "headers": {
              "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying." }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/v1/company/new-hires": {
      "get": {
        "operationId": "getCompanyNewHires",
        "summary": "New hires and promotions at a company (last 90 days) (Beta)",
        "description": "Beta: this endpoint may change.\n\nEveryone we find who joined, or was promoted at, one company in the last 90 days, in one country, checked live.\n\n**Pricing:** 6 credits per call + 1 credit per person returned (a company with no new hires costs 6). Calling again later re-checks the whole 90-day window and is billed again. Not found, invalid input and errors are free.\n\n**Limits:** you need at least 35 credits to start a call, and an account runs one new-hires call at a time (a second concurrent call gets 429 with Retry-After).\n\n**Partial answers:** if your balance can't cover the full result, you get the first page (up to 25 people) with `meta.complete: false` and `meta.credits_needed` — top up and call again for the full results.\n\nPeople come back with ID-style profile URLs (linkedin.com/in/ACwAA…); look one up with `/api/v1/person/profile` for the full profile.",
        "x-credit-cost": "6 + 1 per person",
        "tags": ["Company"],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "A company LinkedIn URL, e.g. https://www.linkedin.com/company/okto/ (a numeric company URL works too).",
            "schema": { "type": "string", "format": "uri" },
            "example": "https://www.linkedin.com/company/okto/"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "2-letter ISO country code of the people to include. Default US.",
            "schema": { "type": "string", "default": "US" },
            "example": "US"
          }
        ],
        "responses": {
          "200": {
            "description": "Checked. 6 credits + 1 per person returned charged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data", "meta"],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": ["company", "new_hires"],
                      "properties": {
                        "company": {
                          "type": "object",
                          "properties": {
                            "url": { "type": "string", "description": "The URL you sent." },
                            "linkedin_id": { "type": "string", "description": "The company's numeric LinkedIn ID." },
                            "name": { "type": ["string", "null"] }
                          }
                        },
                        "new_hires": { "type": "array", "items": { "$ref": "#/components/schemas/NewHire" } }
                      }
                    },
                    "meta": { "$ref": "#/components/schemas/NewHiresMeta" }
                  }
                },
                "example": {
                  "data": {
                    "company": { "url": "https://www.linkedin.com/company/okto/", "linkedin_id": "48213907", "name": "Okto" },
                    "new_hires": [
                      {
                        "person_id": "ACwAAB3kQ9wBf2xLp8Zr0aT4mVyN6cHsE1uQoIk",
                        "first_name": "Priya",
                        "last_name": "Raman",
                        "title": "VP Finance",
                        "type": "new_hire",
                        "started": "2026-08",
                        "location": "Austin, Texas, United States",
                        "linkedin_url": "https://www.linkedin.com/in/ACwAAB3kQ9wBf2xLp8Zr0aT4mVyN6cHsE1uQoIk"
                      },
                      {
                        "person_id": "ACwAAC7nR2sKd5yTq1Wv8bX3eLmP4gZhJ6oUaFs",
                        "first_name": "Marcus",
                        "last_name": "Delgado",
                        "title": "Head of Revenue Operations",
                        "type": "promoted",
                        "started": "2026-10",
                        "location": "Denver, Colorado, United States",
                        "linkedin_url": "https://www.linkedin.com/in/ACwAAC7nR2sKd5yTq1Wv8bX3eLmP4gZhJ6oUaFs"
                      }
                    ]
                  },
                  "meta": {
                    "request_id": "7d1e4b2a-5c3f-4e8d-9a6b-2f1c0e9d8a7b",
                    "country": "US",
                    "window_days": 90,
                    "complete": true,
                    "results": 2,
                    "credits_charged": 8,
                    "credits_remaining": 9991
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "402": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "429": {
            "description": "Another new-hires call from this account is still running. Retry after the interval in the Retry-After header.",
            "headers": {
              "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying." }
            },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your API key, sent as `Authorization: Bearer gma_live_…`. Get one in the dashboard."
      }
    },
    "responses": {
      "Error": {
        "description": "Error. No credit is charged on any error.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "required": ["request_id", "credits_remaining"],
        "properties": {
          "request_id": { "type": "string", "format": "uuid", "description": "Unique id for this request, for support/tracing." },
          "credits_remaining": { "type": "integer", "description": "Account credit balance after this charge." }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "request_id"],
            "properties": {
              "code": {
                "type": "string",
                "description": "Machine-readable error code.",
                "enum": ["invalid_request", "unauthenticated", "insufficient_credits", "profile_not_found", "company_not_found", "rate_limited", "service_unavailable", "internal_error"]
              },
              "message": { "type": "string", "description": "Human-readable explanation." },
              "request_id": { "type": "string", "format": "uuid" }
            }
          }
        }
      },
      "Position": {
        "type": "object",
        "properties": {
          "title": { "type": ["string", "null"] },
          "company_name": { "type": ["string", "null"] },
          "company_linkedin_url": { "type": ["string", "null"] },
          "employment_type": { "type": ["string", "null"] },
          "location": { "type": ["string", "null"] },
          "description": { "type": ["string", "null"] },
          "start_date": { "type": ["string", "null"] },
          "end_date": { "type": ["string", "null"] }
        }
      },
      "JobChange": {
        "type": "object",
        "description": "A current role that started in the last 3 months, as of the time of the call. Start dates are month-precision, so this counts calendar months (in October, a July start counts). new_title: an earlier role at the same company (a promotion or a move inside the company). new_company: no earlier role there. Old roles left marked Present don't change the result.",
        "properties": {
          "type": { "type": "string", "enum": ["new_title", "new_company"] },
          "title": { "type": ["string", "null"] },
          "company_name": { "type": ["string", "null"] },
          "company_linkedin_url": { "type": ["string", "null"] },
          "start_month": { "type": "string", "pattern": "^\\d{4}-\\d{2}$", "examples": ["2026-08"], "description": "Year and month the role started (YYYY-MM)." }
        }
      },
      "Education": {
        "type": "object",
        "properties": {
          "school": { "type": ["string", "null"] },
          "school_linkedin_url": { "type": ["string", "null"] },
          "degree": { "type": ["string", "null"] },
          "field_of_study": { "type": ["string", "null"] },
          "period": { "type": ["string", "null"] }
        }
      },
      "Profile": {
        "type": "object",
        "description": "A normalized public LinkedIn profile.",
        "properties": {
          "public_identifier": { "type": ["string", "null"] },
          "linkedin_url": { "type": ["string", "null"] },
          "first_name": { "type": ["string", "null"] },
          "last_name": { "type": ["string", "null"] },
          "headline": { "type": ["string", "null"] },
          "about": { "type": ["string", "null"] },
          "location": {
            "type": ["object", "null"],
            "properties": {
              "text": { "type": ["string", "null"] },
              "country": { "type": ["string", "null"] },
              "country_code": { "type": ["string", "null"] },
              "state": { "type": ["string", "null"] },
              "city": { "type": ["string", "null"] }
            }
          },
          "premium": { "type": "boolean" },
          "open_to_work": { "type": "boolean" },
          "hiring": { "type": "boolean" },
          "follower_count": { "type": ["integer", "null"] },
          "connections_count": { "type": ["integer", "null"] },
          "current_position": {
            "type": "array",
            "description": "Every role the person currently holds (marked Present). [] if none found.",
            "items": { "$ref": "#/components/schemas/Position" }
          },
          "experience": { "type": "array", "items": { "$ref": "#/components/schemas/Position" } },
          "education": { "type": "array", "items": { "$ref": "#/components/schemas/Education" } },
          "skills": { "type": "array", "items": { "type": "string" } },
          "languages": { "type": "array", "items": { "type": "string" } },
          "insights": {
            "type": "object",
            "description": "Derived by Goma from the profile at the time of the call (everything else is as the profile states it).",
            "properties": {
              "job_change": {
                "description": "Recent job change (last 3 months), or null if none.",
                "oneOf": [{ "$ref": "#/components/schemas/JobChange" }, { "type": "null" }]
              }
            }
          }
        }
      },
      "NewHire": {
        "type": "object",
        "properties": {
          "person_id": { "type": "string", "description": "LinkedIn member ID." },
          "first_name": { "type": ["string", "null"] },
          "last_name": { "type": ["string", "null"] },
          "title": { "type": "string", "description": "Title of the new role." },
          "type": { "type": "string", "enum": ["new_hire", "promoted"], "description": "new_hire = joined the company; promoted = new role after time at the company." },
          "started": { "type": "string", "description": "Month the role started, YYYY-MM." },
          "location": { "type": ["string", "null"] },
          "linkedin_url": { "type": "string", "description": "ID-style profile URL (linkedin.com/in/ACwAA…)." }
        }
      },
      "NewHiresMeta": {
        "type": "object",
        "required": ["request_id", "complete", "results", "credits_charged", "credits_remaining"],
        "properties": {
          "request_id": { "type": "string", "format": "uuid" },
          "country": { "type": "string" },
          "window_days": { "type": "integer" },
          "complete": { "type": "boolean", "description": "False when the balance only covered the first page — see credits_needed." },
          "results": { "type": "integer", "description": "People returned." },
          "credits_charged": { "type": "integer", "description": "6 + results." },
          "credits_remaining": { "type": "integer" },
          "credits_needed": { "type": "integer", "description": "Only when complete is false: credits a full answer could cost (an upper bound)." }
        }
      }
    }
  }
}
