{
  "openapi": "3.0.3",
  "info": {
    "title": "GenLink API",
    "version": "1.0.0",
    "description": "The public GenLink API. Authenticate with a personal API token from Settings → API access in the app, sent as `Authorization: Bearer <token>`. Every call acts as you, in your current workspace.\n\nThis document also describes the drafts API: the small HTTP contract YOUR site implements so GenLink agents can push article drafts and link-insertion proposals into your review queue (see the `x-drafts-api` section and https://backend.genlink.so/llms.txt). Nothing we push is ever published by us."
  },
  "servers": [
    {
      "url": "https://backend.genlink.so/api"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A personal API token from Settings → API access."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "role": {
            "type": "string",
            "description": "user, assistant or tool"
          },
          "type": {
            "type": "string",
            "description": "chat, or a tool/event row type"
          },
          "content": {
            "type": "string",
            "nullable": true
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "time": {
            "type": "integer",
            "nullable": true,
            "description": "created_at as a unix timestamp"
          }
        }
      },
      "Token": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "80-character token id"
          },
          "name": {
            "type": "string"
          },
          "last_used": {
            "type": "string",
            "nullable": true,
            "description": "always null, not tracked"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      }
    }
  },
  "paths": {
    "/manager/messages": {
      "post": {
        "summary": "Send a message to your workspace manager agent",
        "description": "Runs one manager turn and waits for it: a turn can chain several tool calls and take 60-180 seconds, so use a client timeout of at least 300 seconds.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string",
                    "maxLength": 6000
                  },
                  "campaign_uuid": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Optional. Pin the turn to one agent (campaign)."
                  },
                  "table_uuid": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Optional. The table the request is about."
                  }
                }
              },
              "example": {
                "message": "Create an agent targeting seed-stage founders and find 25 leads"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The turn finished.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "reply": {
                      "type": "string",
                      "description": "The manager's final reply text."
                    },
                    "turn_messages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Message"
                      },
                      "description": "Every message this turn created, your own first, oldest first."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation failed, or `No active workspace`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Read the manager conversation",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "minimum": 10,
              "maximum": 500
            },
            "description": "The newest N messages, clamped to 10-500."
          }
        ],
        "responses": {
          "200": {
            "description": "Oldest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "workspace_id": {
                          "type": "integer"
                        },
                        "messages": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Message"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "`No active workspace`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tokens": {
      "get": {
        "summary": "List your API tokens",
        "description": "Only named API tokens that still work. Sign-in sessions are never listed.",
        "responses": {
          "200": {
            "description": "Newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Token"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create an API token",
        "description": "The plaintext token is returned once, in this response only. At most 20 live tokens per user.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 80,
                    "default": "API token"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "token": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "token_id": {
                      "type": "string"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "A reserved name, or `Revoke an old token first` at 20 live tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tokens/{id}": {
      "delete": {
        "summary": "Revoke an API token",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked. The token stops working at once.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not one of your API tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/workspaces": {
      "get": {
        "summary": "List your workspaces",
        "description": "Read-only. Your token acts in current_workspace_id. Switch workspace in the app.",
        "responses": {
          "200": {
            "description": "Your workspaces.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "properties": {
                        "current_workspace_id": {
                          "type": "integer",
                          "description": "The workspace your token acts in. Switch workspace in the app."
                        },
                        "workspaces": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": true,
                            "properties": {
                              "id": {
                                "type": "integer"
                              },
                              "name": {
                                "type": "string"
                              },
                              "slug": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/campaigns": {
      "get": {
        "summary": "List your agents",
        "description": "Read-only. Your agents (campaigns), 20 a page, in your sidebar order.",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A Laravel page of agents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "campaigns": {
                      "type": "object",
                      "additionalProperties": true,
                      "properties": {
                        "current_page": {
                          "type": "integer"
                        },
                        "data": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "One agent. A row carries other keys. They are internal and can change.",
                            "properties": {
                              "uuid": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "running",
                                  "paused"
                                ]
                              },
                              "is_active": {
                                "type": "boolean"
                              },
                              "kind": {
                                "type": "string",
                                "example": "backlinks"
                              },
                              "leads_count": {
                                "type": "integer"
                              },
                              "sent_count": {
                                "type": "integer"
                              },
                              "reply_count": {
                                "type": "integer"
                              },
                              "success_count": {
                                "type": "integer"
                              },
                              "daily_send_cap": {
                                "type": "integer",
                                "nullable": true
                              },
                              "mandate": {
                                "type": "string",
                                "nullable": true,
                                "description": "One-line brief."
                              }
                            }
                          }
                        },
                        "last_page": {
                          "type": "integer"
                        },
                        "per_page": {
                          "type": "integer",
                          "example": 20
                        },
                        "total": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/results": {
      "get": {
        "summary": "Read your results",
        "description": "Read-only. Backlinks won, domain metrics and 90 days of activity (UTC) for your current workspace.",
        "responses": {
          "200": {
            "description": "Results for your current workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "domain": {
                      "type": "string",
                      "nullable": true,
                      "description": "Null until you add a website."
                    },
                    "as_of": {
                      "type": "string",
                      "nullable": true
                    },
                    "metrics": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "change_30d": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true
                    },
                    "series": {
                      "type": "array",
                      "items": {}
                    },
                    "backlinks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "totals": {
                      "type": "object",
                      "additionalProperties": true,
                      "properties": {
                        "won": {
                          "type": "integer"
                        },
                        "attributed": {
                          "type": "integer"
                        },
                        "domains": {
                          "type": "integer"
                        },
                        "value_usd": {
                          "type": "number"
                        }
                      }
                    },
                    "activity": {
                      "type": "object",
                      "additionalProperties": true,
                      "properties": {
                        "timezone": {
                          "type": "string",
                          "example": "UTC"
                        },
                        "days": {
                          "type": "integer",
                          "example": 90
                        },
                        "series": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": true,
                            "properties": {
                              "date": {
                                "type": "string",
                                "format": "date"
                              },
                              "leads": {
                                "type": "integer"
                              },
                              "sends": {
                                "type": "integer"
                              },
                              "replies": {
                                "type": "integer"
                              },
                              "backlinks": {
                                "type": "integer"
                              }
                            }
                          }
                        }
                      }
                    },
                    "next_snapshot_at": {
                      "type": "string",
                      "nullable": true
                    },
                    "ai_visibility": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No workspace yet. Finish onboarding in the app.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "x-drafts-api": {
    "summary": "Receive drafts on your own site. You implement this; GenLink calls it.",
    "setup": "Settings → Integrations → add a key with service `drafts_api`, the secret your endpoint expects, and meta {\"base\":\"https://your-site.example/api/genlink\"} (https only; optional \"language\": en|fr|de|es|pt, default en).",
    "request": {
      "method": "POST",
      "url": "{base}/drafts",
      "headers": {
        "Authorization": "Bearer <the secret you saved>",
        "Idempotency-Key": "1-120 chars, equal to external_id",
        "Content-Type": "application/json",
        "Accept": "application/json"
      },
      "body": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "kind",
          "title",
          "content",
          "language"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "article",
              "link_insertion"
            ]
          },
          "title": {
            "type": "string"
          },
          "content": {
            "type": "string",
            "description": "article: the post body (markdown or HTML). link_insertion: what to add and where."
          },
          "language": {
            "type": "string",
            "enum": [
              "en",
              "fr",
              "de",
              "es",
              "pt"
            ]
          },
          "external_id": {
            "type": "string",
            "maxLength": 120,
            "description": "genlink-ws{workspace}-{sha1(kind|title|content)}: the same proposal always carries the same id."
          },
          "target_url": {
            "type": "string",
            "description": "link_insertion only: the page to edit."
          },
          "source_url": {
            "type": "string",
            "description": "link_insertion only, when known: the URL to link to."
          }
        }
      }
    },
    "responses": {
      "201": "Stored for review (pending_review). Success. Return {id, status_url}.",
      "200": "Idempotent replay of the same Idempotency-Key and content. Success.",
      "409": "Same Idempotency-Key, different content. Reported to the agent as a conflict.",
      "401/403": "Key rejected. The agent is told to save a new key.",
      "other 4xx/5xx": "Reported as a failure with your error message (first 400 characters)."
    },
    "status": {
      "method": "GET",
      "url": "{base}/drafts/{id}",
      "description": "The draft and its review status. Agents call it to check on a proposal."
    },
    "rule": "GenLink never publishes. Everything arrives as a draft for a person on your side to review."
  }
}
