How to Create a GPT

OpenAPI Recipes for GPT Actions (Copy/Paste)

Practical specs you can drop into the GPT builder. Swap api.example.com, keep responses small, and write friendly tool descriptions.

Last updated:

TL;DR

Quick Start: Spec Skeleton

openapi: 3.1.0
info: { title: My API, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
paths: {}
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
  schemas:
    Error:
      type: object
      properties:
        error: { type: string }
        code: { type: string }

Auth Patterns (drop-in)

API Key (header)

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
security:
  - ApiKeyAuth: []

Bearer Token

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
security:
  - BearerAuth: []

OAuth2 (Auth Code)

components:
  securitySchemes:
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://auth.example.com/oauth/authorize
          tokenUrl: https://auth.example.com/oauth/token
          scopes:
            read: Read data
            write: Write data
security:
  - OAuth2: [read, write]

Recipes

Each recipe includes a tool-friendly description, parameters, and compact JSON responses.

1) Weather (read-only, no auth)

Use for demos. Keep outputs tiny: temperature and summary only.

openapi: 3.1.0
info: { title: Weather Action, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
paths:
  /weather:
    get:
      operationId: getWeather
      description: "Gets current weather for a city. Use when user asks about temperature or conditions."
      parameters:
        - in: query
          name: city
          required: true
          schema: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  tempC: { type: number }
                  summary: { type: string }
        '400': { $ref: '#/components/responses/BadRequest' }
components:
  responses:
    BadRequest:
      description: Bad Request
      content:
        application/json:
          schema:
            type: object
            properties:
              error: { type: string }
              code: { type: string }

2) Append to a Sheet (api key)

Great for logs, leads, or feedback. Requires a header API key.

openapi: 3.1.0
info: { title: Sheets Action, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
paths:
  /sheets/{sheetId}/append:
    post:
      operationId: appendRow
      description: "Appends a row of values to the given sheet. Use for logs or signups."
      security: [ { ApiKeyAuth: [] } ]
      parameters:
        - in: path
          name: sheetId
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                values:
                  type: array
                  items: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  rowNumber: { type: integer }

3) Create Support Ticket (bearer)

Collect user issue → create ticket. Include a minimal required set of fields.

openapi: 3.1.0
info: { title: Support Ticket Action, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
paths:
  /tickets:
    post:
      operationId: createTicket
      description: "Creates a support ticket. Use when the user reports a bug or issue."
      security: [ { BearerAuth: [] } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [subject, description]
              properties:
                subject: { type: string }
                description: { type: string }
                priority: { type: string, enum: [low, medium, high] }
                email: { type: string, format: email }
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: { type: string }
                  url: { type: string, format: uri }

4) Search (paginated)

Keep fields minimal: title, url, snippet. Add pagination parameters with sane defaults.

openapi: 3.1.0
info: { title: Search Action, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
paths:
  /search:
    get:
      operationId: search
      description: "Searches the catalog. Use for 'find X' requests."
      parameters:
        - in: query
          name: q
          required: true
          schema: { type: string }
        - in: query
          name: page
          schema: { type: integer, default: 1, minimum: 1 }
        - in: query
          name: pageSize
          schema: { type: integer, default: 5, minimum: 1, maximum: 10 }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        title: { type: string }
                        url: { type: string, format: uri }
                        snippet: { type: string }
                  page: { type: integer }
                  totalPages: { type: integer }

5) Trigger Job (idempotent)

Useful for starting background tasks. Include an Idempotency-Key header to avoid duplicates.

openapi: 3.1.0
info: { title: Jobs Action, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
paths:
  /jobs:
    post:
      operationId: triggerJob
      description: "Triggers a background job. Use when the user asks to start processing."
      parameters:
        - in: header
          name: Idempotency-Key
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type]
              properties:
                type: { type: string, enum: [import, export, analysis] }
                payload: { type: object, additionalProperties: true }
      responses:
        '202':
          description: Accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  jobId: { type: string }
                  status: { type: string, enum: [queued, running] }

6) Send Notification (webhook)

Post a short message to your webhook endpoint. Add per-channel routing if needed.

openapi: 3.1.0
info: { title: Notify Action, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
paths:
  /notify:
    post:
      operationId: sendNotification
      description: "Sends a short message (<= 280 chars) to a webhook or chat relay."
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [message]
              properties:
                channel: { type: string, enum: [alerts, sales, support], default: alerts }
                message: { type: string, maxLength: 280 }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  deliveredAt: { type: string, format: date-time }

7) Create Issue (labels)

Create a tracker issue with optional labels; returns a URL.

openapi: 3.1.0
info: { title: Issues Action, version: '1.0.0' }
servers: [ { url: https://api.example.com } ]
paths:
  /repos/{repo}/issues:
    post:
      operationId: createIssue
      description: "Creates an issue in the repository. Use when the user requests tracking a bug or task."
      parameters:
        - in: path
          name: repo
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title]
              properties:
                title: { type: string }
                body: { type: string }
                labels: { type: array, items: { type: string }, maxItems: 5 }
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id: { type: integer }
                  url: { type: string, format: uri }

Tool Descriptions (tell the GPT when to call)

getWeather: "Fetch current weather for a city: returns { tempC, summary }. Use when user asks about today's weather."
appendRow: "Append a row of values to a sheet: use for logging signups or feedback."
createTicket: "Create a support ticket when a user reports a bug or issue; include subject and description."
search: "Search the catalog and return up to 5 concise results: title, url, snippet."
triggerJob: "Start a background job (import/export/analysis). Use when the user asks to start processing."
sendNotification: "Send a short message to a team channel via webhook."

Error Model & Examples

Standard error schema

components:
  schemas:
    Error:
      type: object
      properties:
        error: { type: string }
        code: { type: string }
        details: { type: object, additionalProperties: true }

Return informative 4xx

responses:
  '400':
    description: Bad Request
    content:
      application/json:
        schema: { $ref: '#/components/schemas/Error' }
        examples:
          missingParam:
            summary: city is required
            value: { error: 'city is required', code: 'MISSING_PARAM' }

Publishing Checklist (for Actions)

  • Public privacy policy URL.
  • Domain verification (TXT record or hosted file).
  • Describe each Action in plain English (what, when, inputs, outputs).
  • Don’t send PII unless essential; never send secrets from users.
  • Log errors server‑side; return concise error messages to the GPT.

FAQ

Where do I host the spec?

Anywhere publicly reachable: your domain or API docs. Keep the URL stable.

How big should responses be?

Small. Prefer the 3–6 fields the GPT needs to answer a question clearly.

Can I secure per‑operation?

Yes. Apply security: at the operation level to override global security.

How do I debug?

Add a short line to the response (during testing) like “source: createTicket” and check your server logs.