{
  "openapi": "3.1.0",
  "info": {
    "title": "SureDocs authorization server",
    "version": "unversioned",
    "description": "The OAuth 2 endpoints a partner exchanges a refresh token at. It has no version in its path, by design."
  },
  "servers": [
    {
      "url": "https://api.suredocs.ie"
    }
  ],
  "tags": [
    {
      "name": "oauth"
    }
  ],
  "paths": {
    "/oauth/token": {
      "post": {
        "operationId": "exchangeRefreshToken",
        "tags": [
          "oauth"
        ],
        "summary": "Exchange a refresh token for an access token.",
        "description": "The OAuth 2 refresh-token grant (RFC 6749 section 6). The access token lasts one hour and acts for the one broker named in broker_id. The response also carries a new refresh token, and the one presented stops working: store the new one durably before you use the access token, and exchange from one place at a time. Send a form (application/x-www-form-urlencoded, the standard) or JSON. Errors use the RFC 6749 section 5.2 shape, not the error shape of the product APIs.\n\nNo token is needed: this endpoint is how you get one.",
        "security": [],
        "x-required-scopes": [],
        "responses": {
          "200": {
            "description": "A new access token and the next refresh token.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Cache-Control": {
                "description": "Always no-store: the response holds credentials.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-store"
                  ]
                }
              },
              "Pragma": {
                "description": "Always no-cache, as RFC 6749 section 5.1 asks.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "no-cache"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request, unsupported_grant_type, invalid_grant, invalid_target or invalid_scope.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenError"
                }
              }
            }
          },
          "401": {
            "description": "invalid_client: the client_id is unknown, is suspended, or does not own the refresh token.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenError"
                }
              }
            }
          },
          "429": {
            "description": "Too many token requests: rate_limited_token, rate_limited_token_daily or rate_limited_token_ip. Retry-After says how many seconds to wait.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Retry-After": {
                "description": "Seconds to wait.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenError"
                }
              }
            }
          },
          "500": {
            "description": "server_error: our fault. Quote the Request-Id header if you report it, and retry with the same refresh token.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/Request-Id"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenError"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "TokenResponse": {
        "title": "TokenResponse",
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in",
          "refresh_token"
        ],
        "properties": {
          "access_token": {
            "type": "string",
            "description": "The bearer token. Treat it as opaque."
          },
          "token_type": {
            "type": "string",
            "enum": [
              "Bearer"
            ]
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds the access token is valid for."
          },
          "refresh_token": {
            "type": "string",
            "description": "The next refresh token. The one you sent no longer works."
          },
          "scope": {
            "type": "string",
            "description": "The scopes granted, separated by spaces. Absent when none were."
          }
        }
      },
      "TokenError": {
        "title": "TokenError",
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "invalid_request",
              "unsupported_grant_type",
              "invalid_client",
              "invalid_grant",
              "invalid_target",
              "invalid_scope",
              "server_error",
              "rate_limited_token",
              "rate_limited_token_daily",
              "rate_limited_token_ip"
            ],
            "description": "The RFC 6749 error code, or, for a 429, the rate limit that refused the request."
          },
          "error_description": {
            "type": "string",
            "description": "For a person to read. Never branch on it."
          }
        }
      },
      "TokenRequest": {
        "title": "TokenRequest",
        "type": "object",
        "required": [
          "grant_type",
          "client_id",
          "refresh_token",
          "broker_id"
        ],
        "properties": {
          "grant_type": {
            "type": "string",
            "enum": [
              "refresh_token"
            ],
            "description": "The only grant supported."
          },
          "client_id": {
            "type": "string",
            "description": "The integration id, in the form int_..., which identifies the integration in the clear."
          },
          "refresh_token": {
            "type": "string",
            "description": "The refresh token: the only secret in the request, and the last one you received."
          },
          "broker_id": {
            "type": "string",
            "description": "The brokerage the access token may act for."
          },
          "scope": {
            "type": "string",
            "description": "Scopes wanted, separated by spaces. Optional: without it, every scope the refresh token and the brokerage share. Asking for one that is not available is an error."
          }
        }
      }
    },
    "headers": {
      "Request-Id": {
        "description": "The id of this request. Quote it if you report a problem: it is what we start an investigation from.",
        "schema": {
          "type": "string"
        },
        "example": "2f4a5f8e-9d3c-4b6e-8f4a-0c5b1e7d2a90"
      },
      "RateLimit-Policy": {
        "description": "Every limit that applies to the request, by name, with its quota q and window w in seconds. An HTTP structured field (RFC 9651): read it with a structured-field parser. Advisory; see Rate limits.",
        "schema": {
          "type": "string"
        },
        "example": "\"burst\";q=60;w=60, \"daily\";q=5000;w=86400"
      },
      "RateLimit": {
        "description": "For each of those limits, how many requests remain (r) and how many seconds until the window resets (t). An HTTP structured field (RFC 9651). Advisory; see Rate limits.",
        "schema": {
          "type": "string"
        },
        "example": "\"burst\";r=41;t=23, \"daily\";r=4870;t=51300"
      }
    }
  }
}
