{
  "openapi": "3.1.0",
  "info": {
    "title": "Portant agent signing API",
    "version": "1.0.0",
    "summary": "Send a document for signature and get the signed PDF back.",
    "description": "The same operations as the Portant MCP server at https://mcp.portant.co/mcp. A person always signs, in a browser; no endpoint applies a signature. Free plan: 30 documents a month. Set up and terms: https://www.portant.co/agents/",
    "contact": {
      "name": "Portant",
      "url": "https://www.portant.co/agents/"
    }
  },
  "servers": [
    {
      "url": "https://mcp.portant.co"
    }
  ],
  "security": [
    {
      "apiKey": []
    },
    {}
  ],
  "paths": {
    "/v1/requests": {
      "post": {
        "operationId": "sendForSignature",
        "summary": "Send a document for signature",
        "description": "Get a document signed by one person, and optionally by the user too. Give the document as markdown text you wrote (use {{signature:signer}} where the signature goes, or leave it out and Portant adds a signature block), a PDF (upload_id for files over 1 MB, pdf_url or pdf_base64), or a Google Doc link shared with \"anyone with the link\". Portant emails the signer a private link; the signer signs in their browser. This tool never signs for anyone. Before you call it, confirm the signer's name and email with the user. Returns request_id, request_token (keep it to download the signed PDF) and next_step (tell it to the user). Limits: two parties, PDFs up to 5 MB and 50 pages, links expire after 14 days. Simple electronic signature.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "document",
                  "signer"
                ],
                "properties": {
                  "document": {
                    "type": "object",
                    "description": "Exactly one of these.",
                    "properties": {
                      "markdown": {
                        "type": "string",
                        "description": "The document as markdown. Put {{signature:signer}}, {{date:signer}}, {{text:signer:Label}}, {{signature:sender}} or {{date:sender}} where each field goes, or leave them out and Portant adds a signature block at the end."
                      },
                      "pdf_base64": {
                        "type": "string",
                        "description": "A PDF as base64. Prefer upload_id or pdf_url for files over 1 MB."
                      },
                      "pdf_url": {
                        "type": "string",
                        "description": "A public https link to a PDF."
                      },
                      "google_doc_url": {
                        "type": "string",
                        "description": "A Google Docs link shared as \"Anyone with the link can view\"."
                      },
                      "upload_id": {
                        "type": "string",
                        "description": "From get_upload_url, after the PDF was uploaded."
                      }
                    }
                  },
                  "title": {
                    "type": "string",
                    "description": "The document title. Required with markdown; it is the heading and the email subject."
                  },
                  "signer": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "description": "The signer's full name."
                      },
                      "email": {
                        "type": "string",
                        "description": "The signer's email address."
                      }
                    },
                    "required": [
                      "email"
                    ]
                  },
                  "sender": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "description": "The user (the sender)'s full name."
                      },
                      "email": {
                        "type": "string",
                        "description": "The user (the sender)'s email address."
                      }
                    },
                    "description": "The user who is sending. Required only when Portant is connected without sign-in; Portant then emails the user to confirm before anything reaches the signer."
                  },
                  "sender_signs": {
                    "type": "boolean",
                    "description": "True when the user signs too. The user signs first, then the signer."
                  },
                  "message": {
                    "type": "string",
                    "description": "A short plain-text note to the signer, up to 500 characters. Links are removed."
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "en",
                      "es",
                      "de",
                      "fr",
                      "ja",
                      "it",
                      "nl",
                      "pt-br"
                    ],
                    "description": "Language of the emails and the signing page. Default en."
                  },
                  "fields": {
                    "type": "array",
                    "description": "Only for PDF or Google Doc input, when you know where the fields go. Positions are fractions of the page from the top-left corner.",
                    "items": {
                      "type": "object",
                      "required": [
                        "kind",
                        "page",
                        "x",
                        "y",
                        "width"
                      ],
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": [
                            "signature",
                            "date",
                            "text"
                          ]
                        },
                        "party": {
                          "type": "string",
                          "enum": [
                            "signer",
                            "sender"
                          ]
                        },
                        "page": {
                          "type": "integer",
                          "minimum": 1
                        },
                        "x": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "y": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "width": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "height": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 1
                        },
                        "label": {
                          "type": "string"
                        },
                        "required": {
                          "type": "boolean"
                        }
                      }
                    }
                  },
                  "delivery": {
                    "type": "string",
                    "enum": [
                      "email",
                      "link"
                    ],
                    "description": "email (default): Portant emails the signer. link: no email; you get the signing link to share."
                  },
                  "certificate": {
                    "type": "boolean",
                    "description": "Append a signing certificate page. Default true."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The request was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "502": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/requests/{request_id}": {
      "get": {
        "operationId": "getSignatureStatus",
        "summary": "Check signature status",
        "description": "Do not check more than once a minute. The sender also gets an email with the signed PDF when it is signed.",
        "parameters": [
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{32}$"
            }
          },
          {
            "name": "X-Request-Token",
            "in": "header",
            "required": false,
            "description": "The request_token from the create response. Needed for a request made without an API key; with the API key of the account that made it, it can be left out (download always needs it).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/requests/{request_id}/signed-pdf": {
      "get": {
        "operationId": "downloadSignedPdf",
        "summary": "Download the signed PDF",
        "description": "After the status is signed. Returns the signed PDF with its signing certificate page.",
        "parameters": [
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{32}$"
            }
          },
          {
            "name": "X-Request-Token",
            "in": "header",
            "required": true,
            "description": "The request_token from the create response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The signed PDF.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/requests/{request_id}/cancel": {
      "post": {
        "operationId": "cancelSignatureRequest",
        "summary": "Cancel a signature request",
        "description": "Cancel a request that is not signed yet. The signing link stops working. A cancel does not give back the monthly count.",
        "parameters": [
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{32}$"
            }
          },
          {
            "name": "X-Request-Token",
            "in": "header",
            "required": false,
            "description": "The request_token from the create response. Needed for a request made without an API key; with the API key of the account that made it, it can be left out (download always needs it).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string"
                    },
                    "status": {
                      "const": "cancelled"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/uploads": {
      "post": {
        "operationId": "getUploadUrl",
        "summary": "Get a PDF upload URL",
        "description": "For PDFs too large to send as base64. PUT the raw PDF bytes to upload_url (with the same Authorization header, if any), then pass upload_id as document.upload_id.",
        "responses": {
          "201": {
            "description": "The upload URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "upload_id": {
                      "type": "string"
                    },
                    "upload_url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "method": {
                      "const": "PUT"
                    },
                    "content_type": {
                      "const": "application/pdf"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "next_step": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/v1/uploads/{upload_id}": {
      "put": {
        "operationId": "uploadPdf",
        "summary": "Upload the PDF",
        "parameters": [
          {
            "name": "upload_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/pdf": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Uploaded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "upload_id": {
                      "type": "string"
                    },
                    "bytes": {
                      "type": "integer"
                    },
                    "next_step": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from https://mcp.portant.co/keys. Without it, a create request needs sender.email, and Portant emails the sender to confirm before the signer gets anything."
      }
    },
    "schemas": {
      "CreateResult": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "request_token": {
            "type": "string",
            "description": "Keep it: it is the only way to download the signed PDF. Portant does not store it."
          },
          "status": {
            "type": "string",
            "enum": [
              "awaiting_sender_confirmation",
              "awaiting_sender_signature",
              "pending"
            ]
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "next_step": {
            "type": "string",
            "description": "A sentence to tell the user."
          },
          "signer_link": {
            "type": "string",
            "format": "uri",
            "description": "Only with delivery \"link\" when the sender does not sign: the private signing link to give the signer."
          },
          "sender_link": {
            "type": "string",
            "format": "uri",
            "description": "Only with delivery \"link\" and sender_signs: the link for the sender to sign first."
          },
          "status_link": {
            "type": "string",
            "format": "uri"
          },
          "usage": {
            "type": "object",
            "properties": {
              "used_this_month": {
                "type": "integer"
              },
              "monthly_limit": {
                "type": "integer"
              }
            }
          }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "awaiting_sender_confirmation",
              "awaiting_sender_signature",
              "pending",
              "signed",
              "cancelled",
              "expired"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "signed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "next_step": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A stable code, for example bad_request, monthly_limit, rate_limited, not_found, bad_token."
          },
          "message": {
            "type": "string",
            "description": "A sentence that says what to do."
          },
          "resets_at": {
            "type": "string",
            "format": "date-time"
          },
          "retryAfter": {
            "type": "integer"
          }
        }
      }
    },
    "responses": {
      "Error": {
        "description": "An error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
