├── .gitignore ├── .openapi-generator-ignore ├── .openapi-generator └── VERSION ├── .travis.yml ├── README.md ├── api └── openapi.yaml ├── api_approve.go ├── client.go ├── configuration.go ├── docs ├── AnswerMetadata.md ├── ApproveApi.md ├── CreatePromptRequest.md ├── Error.md ├── Prompt.md ├── PromptAnswer.md ├── PromptMetadata.md └── PromptStatus.md ├── git_push.sh ├── model_answer_metadata.go ├── model_create_prompt_request.go ├── model_error.go ├── model_prompt.go ├── model_prompt_answer.go ├── model_prompt_metadata.go ├── model_prompt_status.go └── response.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /.openapi-generator-ignore: -------------------------------------------------------------------------------- 1 | # OpenAPI Generator Ignore 2 | # Generated by openapi-generator https://github.com/openapitools/openapi-generator 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /.openapi-generator/VERSION: -------------------------------------------------------------------------------- 1 | 4.0.0-SNAPSHOT -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | install: 4 | - go get -d -v . 5 | 6 | script: 7 | - go build -v ./ 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # approveapi-go 2 | 3 | [![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/approveapi/approveapi-go) 4 | 5 | Go API bindings for the [ApproveAPI HTTP API](https://approveapi.com). 6 | 7 | *ApproveAPI is a simple API to request a user's real-time approval on anything via email, sms + mobile push.* 8 | 9 | ## Features 10 | - [x] Send Prompt 11 | - [x] web redirect actions (i.e. magic links) 12 | - [x] custom approve/reject buttons 13 | - [x] metadata 14 | - [x] long polling 15 | - [x] Retrieve Prompt 16 | - [x] Check Prompt status 17 | - [x] Futures support 18 | - [x] Webhook callbacks 19 | 20 | ## Install 21 | 22 | Install the dependencies: 23 | ``` 24 | go get "github.com/approveapi/approveapi-go" 25 | ``` 26 | 27 | ## Import: 28 | ```golang 29 | import "github.com/approveapi/approveapi-go" 30 | ``` 31 | 32 | ## Getting Started 33 | 34 | To get started, we create a client: 35 | 36 | ```go 37 | client := approveapi.CreateClient("sk_test_yourapikeyhere") 38 | ``` 39 | 40 | Now we can make API calls. For example, let's send an approval prompt to confirm a financial transaction. 41 | 42 | ```go 43 | longPoll := true 44 | prompt, _, err := client.ApproveApi.CreatePrompt( 45 | approveapi.CreatePromptRequest { 46 | User: "alice@approveapi.com", 47 | Body: `A transfer of $1337.45 from acct 0294 to acct 1045 48 | has been initiated. Do you want to authorize this transfer?`, 49 | ApproveText: "Authorize", 50 | RejectText: "Reject", 51 | LongPoll: &longPoll, 52 | }, 53 | ) 54 | if err != nil { 55 | fmt.Printf("%#v\n", err) 56 | return 57 | } 58 | if prompt.Answer != nil { 59 | if prompt.Answer.Result { 60 | fmt.Println("Request approved") 61 | } else { 62 | fmt.Println("Request rejected") 63 | } 64 | } else { 65 | fmt.Println("No response yet") 66 | } 67 | 68 | ``` 69 | 70 | ## Documentation 71 | 72 | Full documentation is available here: [approveapi.com/docs](https://www.approveapi.com/docs/?go). 73 | 74 | 75 | -------------------------------------------------------------------------------- /api/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | contact: 4 | email: dev@approveapi.com 5 | description: The simple API to request a user's approval on anything via email + sms. 6 | title: ApproveAPISwagger 7 | version: 1.0.1 8 | servers: 9 | - url: https://approve.sh 10 | paths: 11 | /prompt/{id}: 12 | get: 13 | description: Retrieve the prompt object with the given ID. 14 | operationId: GetPrompt 15 | parameters: 16 | - description: The identifier for a pending or completed prompt. This is returned when you create a prompt. 17 | explode: false 18 | in: path 19 | name: id 20 | required: true 21 | schema: 22 | type: string 23 | style: simple 24 | - description: If true, the request waits (long-polls) until the user responds to the prompt or more than 10 minutes pass. Defaults to false. 25 | explode: true 26 | in: query 27 | name: long_poll 28 | required: false 29 | schema: 30 | type: boolean 31 | style: form 32 | responses: 33 | 200: 34 | content: 35 | application/json: 36 | schema: 37 | $ref: '#/components/schemas/Prompt' 38 | description: OK 39 | 404: 40 | content: 41 | application/json: 42 | schema: 43 | $ref: '#/components/schemas/Error' 44 | description: A prompt with this identifier could not be found 45 | 400: 46 | content: 47 | application/json: 48 | schema: 49 | $ref: '#/components/schemas/Error' 50 | description: Invalid parameters 51 | security: 52 | - apiKey: [] 53 | summary: Retrieve a prompt 54 | tags: 55 | - approve 56 | /prompt/{id}/status: 57 | get: 58 | description: Returns whether a prompt has been completed by the user. This request does not require authentication, and so can be used client-side without sharing API credentials. 59 | operationId: GetPromptStatus 60 | parameters: 61 | - description: The prompt identifier. 62 | explode: false 63 | in: path 64 | name: id 65 | required: true 66 | schema: 67 | type: string 68 | style: simple 69 | responses: 70 | 200: 71 | content: 72 | application/json: 73 | schema: 74 | $ref: '#/components/schemas/PromptStatus' 75 | description: OK 76 | 404: 77 | content: 78 | application/json: 79 | schema: 80 | $ref: '#/components/schemas/Error' 81 | description: A prompt with this identifier could not be found 82 | 400: 83 | content: 84 | application/json: 85 | schema: 86 | $ref: '#/components/schemas/Error' 87 | description: Invalid parameters 88 | summary: Check prompt status 89 | tags: 90 | - approve 91 | /prompt: 92 | post: 93 | description: Creates a prompt and pushes it to the user (sends via email, sms, or other supported protocols). 94 | operationId: CreatePrompt 95 | requestBody: 96 | content: 97 | application/json: 98 | schema: 99 | $ref: '#/components/schemas/CreatePromptRequest' 100 | required: true 101 | responses: 102 | 200: 103 | content: 104 | application/json: 105 | schema: 106 | $ref: '#/components/schemas/Prompt' 107 | description: OK 108 | 504: 109 | content: 110 | application/json: 111 | schema: 112 | $ref: '#/components/schemas/Error' 113 | description: Polling timed out with no user response 114 | 401: 115 | content: 116 | application/json: 117 | schema: 118 | $ref: '#/components/schemas/Error' 119 | description: Missing or invalid API key in the username basic auth field 120 | 400: 121 | content: 122 | application/json: 123 | schema: 124 | $ref: '#/components/schemas/Error' 125 | description: Invalid parameters 126 | security: 127 | - apiKey: [] 128 | summary: Sending a prompt 129 | tags: 130 | - approve 131 | components: 132 | responses: 133 | PromptNotFound: 134 | content: 135 | application/json: 136 | schema: 137 | $ref: '#/components/schemas/Error' 138 | description: A prompt with this identifier could not be found 139 | PollTimeout: 140 | content: 141 | application/json: 142 | schema: 143 | $ref: '#/components/schemas/Error' 144 | description: Polling timed out with no user response 145 | Unauthorized: 146 | content: 147 | application/json: 148 | schema: 149 | $ref: '#/components/schemas/Error' 150 | description: Missing or invalid API key in the username basic auth field 151 | BadRequest: 152 | content: 153 | application/json: 154 | schema: 155 | $ref: '#/components/schemas/Error' 156 | description: Invalid parameters 157 | schemas: 158 | PromptInternalData: 159 | additionalProperties: 160 | type: string 161 | type: object 162 | Prompt: 163 | example: 164 | sent_at: 0.8008281904610115 165 | request: 166 | metadata: 167 | browser: browser 168 | operating_system: operating_system 169 | location: location 170 | time: time 171 | ip_address: ip_address 172 | long_poll: true 173 | reject_text: reject_text 174 | internal_data: 175 | key: internal_data 176 | approve_redirect_url: approve_redirect_url 177 | reject_redirect_url: reject_redirect_url 178 | idempotency_key: idempotency_key 179 | approve_text: approve_text 180 | body: body 181 | title: title 182 | expires_in: 1.4658129805029452 183 | user: user 184 | metadata: 185 | browser: browser 186 | operating_system: operating_system 187 | location: location 188 | time: time 189 | ip_address: ip_address 190 | is_expired: true 191 | answer: 192 | result: true 193 | metadata: 194 | slack_real_name: slack_real_name 195 | browser: browser 196 | operating_system: operating_system 197 | ip_address: ip_address 198 | slack_email: slack_email 199 | slack_username: slack_username 200 | time: 6.027456183070403 201 | id: id 202 | properties: 203 | sent_at: 204 | description: The unix timestamp when this prompt was sent. 205 | type: number 206 | answer: 207 | $ref: '#/components/schemas/PromptAnswer' 208 | is_expired: 209 | description: Whether the prompt can still be answered. 210 | type: boolean 211 | request: 212 | $ref: '#/components/schemas/CreatePromptRequest' 213 | id: 214 | description: A unique id for this prompt. 215 | type: string 216 | metadata: 217 | $ref: '#/components/schemas/PromptMetadata' 218 | required: 219 | - id 220 | - is_expired 221 | - request 222 | - sent_at 223 | type: object 224 | PromptMetadata: 225 | example: 226 | browser: browser 227 | operating_system: operating_system 228 | location: location 229 | time: time 230 | ip_address: ip_address 231 | properties: 232 | time: 233 | description: The date/time of the action. 234 | type: string 235 | operating_system: 236 | description: The operating system initiating the action, i.e. Mac OS X. 237 | type: string 238 | ip_address: 239 | description: The IP address of the computer initiating the action. 240 | type: string 241 | location: 242 | description: The physical location, like Oakland, CA, of the action. 243 | type: string 244 | browser: 245 | description: The web browser initiating the action, i.e. Chrome. 246 | type: string 247 | type: object 248 | CreatePromptRequest: 249 | example: 250 | metadata: 251 | browser: browser 252 | operating_system: operating_system 253 | location: location 254 | time: time 255 | ip_address: ip_address 256 | long_poll: true 257 | reject_text: reject_text 258 | internal_data: 259 | key: internal_data 260 | approve_redirect_url: approve_redirect_url 261 | reject_redirect_url: reject_redirect_url 262 | idempotency_key: idempotency_key 263 | approve_text: approve_text 264 | body: body 265 | title: title 266 | expires_in: 1.4658129805029452 267 | user: user 268 | properties: 269 | body: 270 | description: The body of the approval request to show the user. 271 | type: string 272 | idempotency_key: 273 | description: Allows calling `create_prompt` multiple times idempotently, such that a prompt is sent at-most once. This key should contain sufficient randomness. Idempotent requests are stored for 24 hours. After that time, the same key will create a new request. 274 | type: string 275 | title: 276 | description: The title of an approval request. Defaults to an empty string. 277 | type: string 278 | reject_text: 279 | description: The reject action text. If not specified the reject button will NOT be rendered, and the user will only see an approve action button. 280 | type: string 281 | expires_in: 282 | description: The number of seconds until this request can no longer be answered. 283 | type: number 284 | long_poll: 285 | description: If true, the request waits (long-polls) until the user responds to the prompt or more than 10 minutes pass. Defaults to false. 286 | type: boolean 287 | internal_data: 288 | additionalProperties: 289 | type: string 290 | type: object 291 | user: 292 | description: The user to send the approval request to. Can be either an email address or a phone number. 293 | type: string 294 | approve_text: 295 | description: The approve action text. Defaults to 'Approve'. 296 | type: string 297 | approve_redirect_url: 298 | description: An HTTPS URL to redirect the user to if the prompt is approved. This URL is kept secret until the user is redirected to it. 299 | type: string 300 | reject_redirect_url: 301 | description: An HTTPS URL to redirect the user to if the prompt is rejected. This URL is kept secret until the user is redirected to it. 302 | type: string 303 | metadata: 304 | $ref: '#/components/schemas/PromptMetadata' 305 | required: 306 | - body 307 | - user 308 | type: object 309 | Error: 310 | properties: 311 | error: 312 | description: A human readable API error message. 313 | type: string 314 | required: 315 | - error 316 | type: object 317 | PromptStatus: 318 | example: 319 | is_expired: true 320 | is_answered: true 321 | properties: 322 | is_answered: 323 | description: Whether the prompt has been answered or not. 324 | type: boolean 325 | is_expired: 326 | description: Whether the prompt can still be answered. 327 | type: boolean 328 | required: 329 | - is_answered 330 | - is_expired 331 | type: object 332 | AnswerMetadata: 333 | example: 334 | slack_real_name: slack_real_name 335 | browser: browser 336 | operating_system: operating_system 337 | ip_address: ip_address 338 | slack_email: slack_email 339 | slack_username: slack_username 340 | properties: 341 | slack_real_name: 342 | type: string 343 | operating_system: 344 | type: string 345 | slack_username: 346 | type: string 347 | ip_address: 348 | type: string 349 | slack_email: 350 | type: string 351 | browser: 352 | type: string 353 | type: object 354 | PromptAnswer: 355 | example: 356 | result: true 357 | metadata: 358 | slack_real_name: slack_real_name 359 | browser: browser 360 | operating_system: operating_system 361 | ip_address: ip_address 362 | slack_email: slack_email 363 | slack_username: slack_username 364 | time: 6.027456183070403 365 | properties: 366 | time: 367 | description: The unix timestamp when the user answered the prompt. 368 | type: number 369 | result: 370 | description: The user's answer to whether or not they approve this prompt. 371 | type: boolean 372 | metadata: 373 | $ref: '#/components/schemas/AnswerMetadata' 374 | required: 375 | - result 376 | - time 377 | type: object 378 | securitySchemes: 379 | apiKey: 380 | scheme: basic 381 | type: http 382 | -------------------------------------------------------------------------------- /api_approve.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | import ( 14 | "context" 15 | "io/ioutil" 16 | "net/http" 17 | "net/url" 18 | "strings" 19 | "time" 20 | "fmt" 21 | "github.com/antihax/optional" 22 | ) 23 | 24 | // Linger please 25 | var ( 26 | _ context.Context 27 | ) 28 | 29 | type ApproveApiService service 30 | 31 | /* 32 | ApproveApiService Sending a prompt 33 | Creates a prompt and pushes it to the user (sends via email, sms, or other supported protocols). 34 | * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). 35 | * @param createPromptRequest 36 | @return Prompt 37 | */ 38 | func (a *ApproveApiService) CreatePromptWithContext(ctx context.Context, createPromptRequest CreatePromptRequest) (Prompt, *http.Response, error) { 39 | var ( 40 | localVarHttpMethod = strings.ToUpper("Post") 41 | localVarPostBody interface{} 42 | localVarFormFileName string 43 | localVarFileName string 44 | localVarFileBytes []byte 45 | localVarReturnValue Prompt 46 | ) 47 | 48 | // create path and map variables 49 | localVarPath := a.client.cfg.BasePath + "/prompt" 50 | 51 | localVarHeaderParams := make(map[string]string) 52 | localVarQueryParams := url.Values{} 53 | localVarFormParams := url.Values{} 54 | 55 | // to determine the Content-Type header 56 | localVarHttpContentTypes := []string{"application/json"} 57 | 58 | // set Content-Type header 59 | localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) 60 | if localVarHttpContentType != "" { 61 | localVarHeaderParams["Content-Type"] = localVarHttpContentType 62 | } 63 | 64 | // to determine the Accept header 65 | localVarHttpHeaderAccepts := []string{"application/json"} 66 | 67 | // set Accept header 68 | localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) 69 | if localVarHttpHeaderAccept != "" { 70 | localVarHeaderParams["Accept"] = localVarHttpHeaderAccept 71 | } 72 | // body params 73 | localVarPostBody = &createPromptRequest 74 | r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes) 75 | if err != nil { 76 | return localVarReturnValue, nil, err 77 | } 78 | 79 | localVarHttpResponse, err := a.client.callAPI(r) 80 | if err != nil || localVarHttpResponse == nil { 81 | return localVarReturnValue, localVarHttpResponse, err 82 | } 83 | 84 | localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) 85 | localVarHttpResponse.Body.Close() 86 | if err != nil { 87 | return localVarReturnValue, localVarHttpResponse, err 88 | } 89 | 90 | if localVarHttpResponse.StatusCode >= 300 { 91 | newErr := ApproveApiError{ 92 | body: localVarBody, 93 | error: localVarHttpResponse.Status, 94 | } 95 | if localVarHttpResponse.StatusCode == 200 { 96 | var v Prompt 97 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 98 | if err != nil { 99 | newErr.error = err.Error() 100 | return localVarReturnValue, localVarHttpResponse, newErr 101 | } 102 | newErr.model = v 103 | return localVarReturnValue, localVarHttpResponse, newErr 104 | } 105 | if localVarHttpResponse.StatusCode == 504 { 106 | var v Error 107 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 108 | if err != nil { 109 | newErr.error = err.Error() 110 | return localVarReturnValue, localVarHttpResponse, newErr 111 | } 112 | newErr.model = v 113 | return localVarReturnValue, localVarHttpResponse, newErr 114 | } 115 | if localVarHttpResponse.StatusCode == 401 { 116 | var v Error 117 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 118 | if err != nil { 119 | newErr.error = err.Error() 120 | return localVarReturnValue, localVarHttpResponse, newErr 121 | } 122 | newErr.model = v 123 | return localVarReturnValue, localVarHttpResponse, newErr 124 | } 125 | if localVarHttpResponse.StatusCode == 400 { 126 | var v Error 127 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 128 | if err != nil { 129 | newErr.error = err.Error() 130 | return localVarReturnValue, localVarHttpResponse, newErr 131 | } 132 | newErr.model = v 133 | return localVarReturnValue, localVarHttpResponse, newErr 134 | } 135 | return localVarReturnValue, localVarHttpResponse, newErr 136 | } 137 | 138 | err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 139 | if err != nil { 140 | newErr := ApproveApiError{ 141 | body: localVarBody, 142 | error: err.Error(), 143 | } 144 | return localVarReturnValue, localVarHttpResponse, newErr 145 | } 146 | 147 | return localVarReturnValue, localVarHttpResponse, nil 148 | } 149 | 150 | func (a *ApproveApiService) CreatePrompt(createPromptRequest CreatePromptRequest) (Prompt, *http.Response, error) { 151 | ctx, cancel := context.WithTimeout(context.Background(), 11*time.Minute) 152 | defer cancel() 153 | return a.CreatePromptWithContext(ctx, createPromptRequest) 154 | } 155 | 156 | 157 | /* 158 | ApproveApiService Retrieve a prompt 159 | Retrieve the prompt object with the given ID. 160 | * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). 161 | * @param id The identifier for a pending or completed prompt. This is returned when you create a prompt. 162 | * @param optional nil or *GetPromptOpts - Optional Parameters: 163 | * @param "LongPoll" (optional.Bool) - If true, the request waits (long-polls) until the user responds to the prompt or more than 10 minutes pass. Defaults to false. 164 | @return Prompt 165 | */ 166 | 167 | type GetPromptOpts struct { 168 | LongPoll optional.Bool 169 | } 170 | 171 | func (a *ApproveApiService) GetPromptWithContext(ctx context.Context, id string, localVarOptionals *GetPromptOpts) (Prompt, *http.Response, error) { 172 | var ( 173 | localVarHttpMethod = strings.ToUpper("Get") 174 | localVarPostBody interface{} 175 | localVarFormFileName string 176 | localVarFileName string 177 | localVarFileBytes []byte 178 | localVarReturnValue Prompt 179 | ) 180 | 181 | // create path and map variables 182 | localVarPath := a.client.cfg.BasePath + "/prompt/{id}" 183 | localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", fmt.Sprintf("%v", id), -1) 184 | 185 | localVarHeaderParams := make(map[string]string) 186 | localVarQueryParams := url.Values{} 187 | localVarFormParams := url.Values{} 188 | 189 | if localVarOptionals != nil && localVarOptionals.LongPoll.IsSet() { 190 | localVarQueryParams.Add("long_poll", parameterToString(localVarOptionals.LongPoll.Value(), "")) 191 | } 192 | // to determine the Content-Type header 193 | localVarHttpContentTypes := []string{} 194 | 195 | // set Content-Type header 196 | localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) 197 | if localVarHttpContentType != "" { 198 | localVarHeaderParams["Content-Type"] = localVarHttpContentType 199 | } 200 | 201 | // to determine the Accept header 202 | localVarHttpHeaderAccepts := []string{"application/json"} 203 | 204 | // set Accept header 205 | localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) 206 | if localVarHttpHeaderAccept != "" { 207 | localVarHeaderParams["Accept"] = localVarHttpHeaderAccept 208 | } 209 | r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes) 210 | if err != nil { 211 | return localVarReturnValue, nil, err 212 | } 213 | 214 | localVarHttpResponse, err := a.client.callAPI(r) 215 | if err != nil || localVarHttpResponse == nil { 216 | return localVarReturnValue, localVarHttpResponse, err 217 | } 218 | 219 | localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) 220 | localVarHttpResponse.Body.Close() 221 | if err != nil { 222 | return localVarReturnValue, localVarHttpResponse, err 223 | } 224 | 225 | if localVarHttpResponse.StatusCode >= 300 { 226 | newErr := ApproveApiError{ 227 | body: localVarBody, 228 | error: localVarHttpResponse.Status, 229 | } 230 | if localVarHttpResponse.StatusCode == 200 { 231 | var v Prompt 232 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 233 | if err != nil { 234 | newErr.error = err.Error() 235 | return localVarReturnValue, localVarHttpResponse, newErr 236 | } 237 | newErr.model = v 238 | return localVarReturnValue, localVarHttpResponse, newErr 239 | } 240 | if localVarHttpResponse.StatusCode == 404 { 241 | var v Error 242 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 243 | if err != nil { 244 | newErr.error = err.Error() 245 | return localVarReturnValue, localVarHttpResponse, newErr 246 | } 247 | newErr.model = v 248 | return localVarReturnValue, localVarHttpResponse, newErr 249 | } 250 | if localVarHttpResponse.StatusCode == 400 { 251 | var v Error 252 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 253 | if err != nil { 254 | newErr.error = err.Error() 255 | return localVarReturnValue, localVarHttpResponse, newErr 256 | } 257 | newErr.model = v 258 | return localVarReturnValue, localVarHttpResponse, newErr 259 | } 260 | return localVarReturnValue, localVarHttpResponse, newErr 261 | } 262 | 263 | err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 264 | if err != nil { 265 | newErr := ApproveApiError{ 266 | body: localVarBody, 267 | error: err.Error(), 268 | } 269 | return localVarReturnValue, localVarHttpResponse, newErr 270 | } 271 | 272 | return localVarReturnValue, localVarHttpResponse, nil 273 | } 274 | 275 | func (a *ApproveApiService) GetPrompt(id string, localVarOptionals *GetPromptOpts) (Prompt, *http.Response, error) { 276 | ctx, cancel := context.WithTimeout(context.Background(), 11*time.Minute) 277 | defer cancel() 278 | return a.GetPromptWithContext(ctx, id, localVarOptionals) 279 | } 280 | 281 | 282 | /* 283 | ApproveApiService Check prompt status 284 | Returns whether a prompt has been completed by the user. This request does not require authentication, and so can be used client-side without sharing API credentials. 285 | * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). 286 | * @param id The prompt identifier. 287 | @return PromptStatus 288 | */ 289 | func (a *ApproveApiService) GetPromptStatusWithContext(ctx context.Context, id string) (PromptStatus, *http.Response, error) { 290 | var ( 291 | localVarHttpMethod = strings.ToUpper("Get") 292 | localVarPostBody interface{} 293 | localVarFormFileName string 294 | localVarFileName string 295 | localVarFileBytes []byte 296 | localVarReturnValue PromptStatus 297 | ) 298 | 299 | // create path and map variables 300 | localVarPath := a.client.cfg.BasePath + "/prompt/{id}/status" 301 | localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", fmt.Sprintf("%v", id), -1) 302 | 303 | localVarHeaderParams := make(map[string]string) 304 | localVarQueryParams := url.Values{} 305 | localVarFormParams := url.Values{} 306 | 307 | // to determine the Content-Type header 308 | localVarHttpContentTypes := []string{} 309 | 310 | // set Content-Type header 311 | localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) 312 | if localVarHttpContentType != "" { 313 | localVarHeaderParams["Content-Type"] = localVarHttpContentType 314 | } 315 | 316 | // to determine the Accept header 317 | localVarHttpHeaderAccepts := []string{"application/json"} 318 | 319 | // set Accept header 320 | localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) 321 | if localVarHttpHeaderAccept != "" { 322 | localVarHeaderParams["Accept"] = localVarHttpHeaderAccept 323 | } 324 | r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes) 325 | if err != nil { 326 | return localVarReturnValue, nil, err 327 | } 328 | 329 | localVarHttpResponse, err := a.client.callAPI(r) 330 | if err != nil || localVarHttpResponse == nil { 331 | return localVarReturnValue, localVarHttpResponse, err 332 | } 333 | 334 | localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) 335 | localVarHttpResponse.Body.Close() 336 | if err != nil { 337 | return localVarReturnValue, localVarHttpResponse, err 338 | } 339 | 340 | if localVarHttpResponse.StatusCode >= 300 { 341 | newErr := ApproveApiError{ 342 | body: localVarBody, 343 | error: localVarHttpResponse.Status, 344 | } 345 | if localVarHttpResponse.StatusCode == 200 { 346 | var v PromptStatus 347 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 348 | if err != nil { 349 | newErr.error = err.Error() 350 | return localVarReturnValue, localVarHttpResponse, newErr 351 | } 352 | newErr.model = v 353 | return localVarReturnValue, localVarHttpResponse, newErr 354 | } 355 | if localVarHttpResponse.StatusCode == 404 { 356 | var v Error 357 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 358 | if err != nil { 359 | newErr.error = err.Error() 360 | return localVarReturnValue, localVarHttpResponse, newErr 361 | } 362 | newErr.model = v 363 | return localVarReturnValue, localVarHttpResponse, newErr 364 | } 365 | if localVarHttpResponse.StatusCode == 400 { 366 | var v Error 367 | err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 368 | if err != nil { 369 | newErr.error = err.Error() 370 | return localVarReturnValue, localVarHttpResponse, newErr 371 | } 372 | newErr.model = v 373 | return localVarReturnValue, localVarHttpResponse, newErr 374 | } 375 | return localVarReturnValue, localVarHttpResponse, newErr 376 | } 377 | 378 | err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")) 379 | if err != nil { 380 | newErr := ApproveApiError{ 381 | body: localVarBody, 382 | error: err.Error(), 383 | } 384 | return localVarReturnValue, localVarHttpResponse, newErr 385 | } 386 | 387 | return localVarReturnValue, localVarHttpResponse, nil 388 | } 389 | 390 | func (a *ApproveApiService) GetPromptStatus(id string) (PromptStatus, *http.Response, error) { 391 | ctx, cancel := context.WithTimeout(context.Background(), 11*time.Minute) 392 | defer cancel() 393 | return a.GetPromptStatusWithContext(ctx, id) 394 | } 395 | 396 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | import ( 14 | "bytes" 15 | "context" 16 | "encoding/json" 17 | "encoding/xml" 18 | "errors" 19 | "fmt" 20 | "io" 21 | "mime/multipart" 22 | "net/http" 23 | "net/url" 24 | "os" 25 | "path/filepath" 26 | "reflect" 27 | "regexp" 28 | "strconv" 29 | "strings" 30 | "time" 31 | "unicode/utf8" 32 | 33 | "golang.org/x/oauth2" 34 | ) 35 | 36 | var ( 37 | jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") 38 | xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") 39 | ) 40 | 41 | // APIClient manages communication with the ApproveAPISwagger API v1.0.1 42 | // In most cases there should be only one, shared, APIClient. 43 | type APIClient struct { 44 | cfg *Configuration 45 | common service // Reuse a single struct instead of allocating one for each service on the heap. 46 | 47 | // API Services 48 | 49 | ApproveApi *ApproveApiService 50 | } 51 | 52 | type service struct { 53 | client *APIClient 54 | } 55 | 56 | // NewAPIClient creates a new API client. Requires a userAgent string describing your application. 57 | // optionally a custom http.Client to allow for advanced features such as caching. 58 | func NewAPIClient(cfg *Configuration) *APIClient { 59 | if cfg.HTTPClient == nil { 60 | cfg.HTTPClient = http.DefaultClient 61 | } 62 | 63 | c := &APIClient{} 64 | c.cfg = cfg 65 | c.common.client = c 66 | 67 | // API Services 68 | c.ApproveApi = (*ApproveApiService)(&c.common) 69 | 70 | return c 71 | } 72 | 73 | func CreateClient(apiKey string) *APIClient { 74 | cfg := NewConfiguration() 75 | cfg.Authentication.BasicAuth = &BasicAuth { 76 | UserName: apiKey, 77 | } 78 | return NewAPIClient(cfg) 79 | } 80 | 81 | func atoi(in string) (int, error) { 82 | return strconv.Atoi(in) 83 | } 84 | 85 | // selectHeaderContentType select a content type from the available list. 86 | func selectHeaderContentType(contentTypes []string) string { 87 | if len(contentTypes) == 0 { 88 | return "" 89 | } 90 | if contains(contentTypes, "application/json") { 91 | return "application/json" 92 | } 93 | return contentTypes[0] // use the first content type specified in 'consumes' 94 | } 95 | 96 | // selectHeaderAccept join all accept types and return 97 | func selectHeaderAccept(accepts []string) string { 98 | if len(accepts) == 0 { 99 | return "" 100 | } 101 | 102 | if contains(accepts, "application/json") { 103 | return "application/json" 104 | } 105 | 106 | return strings.Join(accepts, ",") 107 | } 108 | 109 | // contains is a case insenstive match, finding needle in a haystack 110 | func contains(haystack []string, needle string) bool { 111 | for _, a := range haystack { 112 | if strings.ToLower(a) == strings.ToLower(needle) { 113 | return true 114 | } 115 | } 116 | return false 117 | } 118 | 119 | // Verify optional parameters are of the correct type. 120 | func typeCheckParameter(obj interface{}, expected string, name string) error { 121 | // Make sure there is an object. 122 | if obj == nil { 123 | return nil 124 | } 125 | 126 | // Check the type is as expected. 127 | if reflect.TypeOf(obj).String() != expected { 128 | return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) 129 | } 130 | return nil 131 | } 132 | 133 | // parameterToString convert interface{} parameters to string, using a delimiter if format is provided. 134 | func parameterToString(obj interface{}, collectionFormat string) string { 135 | var delimiter string 136 | 137 | switch collectionFormat { 138 | case "pipes": 139 | delimiter = "|" 140 | case "ssv": 141 | delimiter = " " 142 | case "tsv": 143 | delimiter = "\t" 144 | case "csv": 145 | delimiter = "," 146 | } 147 | 148 | if reflect.TypeOf(obj).Kind() == reflect.Slice { 149 | return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") 150 | } else if t, ok := obj.(time.Time); ok { 151 | return t.Format(time.RFC3339) 152 | } 153 | 154 | return fmt.Sprintf("%v", obj) 155 | } 156 | 157 | // callAPI do the request. 158 | func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { 159 | return c.cfg.HTTPClient.Do(request) 160 | } 161 | 162 | // Change base path to allow switching to mocks 163 | func (c *APIClient) ChangeBasePath(path string) { 164 | c.cfg.BasePath = path 165 | } 166 | 167 | // prepareRequest build the request 168 | func (c *APIClient) prepareRequest( 169 | ctx context.Context, 170 | path string, method string, 171 | postBody interface{}, 172 | headerParams map[string]string, 173 | queryParams url.Values, 174 | formParams url.Values, 175 | formFileName string, 176 | fileName string, 177 | fileBytes []byte) (localVarRequest *http.Request, err error) { 178 | 179 | var body *bytes.Buffer 180 | 181 | // Detect postBody type and post. 182 | if postBody != nil { 183 | contentType := headerParams["Content-Type"] 184 | if contentType == "" { 185 | contentType = detectContentType(postBody) 186 | headerParams["Content-Type"] = contentType 187 | } 188 | 189 | body, err = setBody(postBody, contentType) 190 | if err != nil { 191 | return nil, err 192 | } 193 | } 194 | 195 | // add form parameters and file if available. 196 | if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { 197 | if body != nil { 198 | return nil, errors.New("Cannot specify postBody and multipart form at the same time.") 199 | } 200 | body = &bytes.Buffer{} 201 | w := multipart.NewWriter(body) 202 | 203 | for k, v := range formParams { 204 | for _, iv := range v { 205 | if strings.HasPrefix(k, "@") { // file 206 | err = addFile(w, k[1:], iv) 207 | if err != nil { 208 | return nil, err 209 | } 210 | } else { // form value 211 | w.WriteField(k, iv) 212 | } 213 | } 214 | } 215 | if len(fileBytes) > 0 && fileName != "" { 216 | w.Boundary() 217 | //_, fileNm := filepath.Split(fileName) 218 | part, err := w.CreateFormFile(formFileName, filepath.Base(fileName)) 219 | if err != nil { 220 | return nil, err 221 | } 222 | _, err = part.Write(fileBytes) 223 | if err != nil { 224 | return nil, err 225 | } 226 | // Set the Boundary in the Content-Type 227 | headerParams["Content-Type"] = w.FormDataContentType() 228 | } 229 | 230 | // Set Content-Length 231 | headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 232 | w.Close() 233 | } 234 | 235 | if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { 236 | if body != nil { 237 | return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.") 238 | } 239 | body = &bytes.Buffer{} 240 | body.WriteString(formParams.Encode()) 241 | // Set Content-Length 242 | headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 243 | } 244 | 245 | // Setup path and query parameters 246 | url, err := url.Parse(path) 247 | if err != nil { 248 | return nil, err 249 | } 250 | 251 | // Adding Query Param 252 | query := url.Query() 253 | for k, v := range queryParams { 254 | for _, iv := range v { 255 | query.Add(k, iv) 256 | } 257 | } 258 | 259 | // Encode the parameters. 260 | url.RawQuery = query.Encode() 261 | 262 | // Generate a new request 263 | if body != nil { 264 | localVarRequest, err = http.NewRequest(method, url.String(), body) 265 | } else { 266 | localVarRequest, err = http.NewRequest(method, url.String(), nil) 267 | } 268 | if err != nil { 269 | return nil, err 270 | } 271 | 272 | // add header parameters, if any 273 | if len(headerParams) > 0 { 274 | headers := http.Header{} 275 | for h, v := range headerParams { 276 | headers.Set(h, v) 277 | } 278 | localVarRequest.Header = headers 279 | } 280 | 281 | // Override request host, if applicable 282 | if c.cfg.Host != "" { 283 | localVarRequest.Host = c.cfg.Host 284 | } 285 | 286 | // Add the user agent to the request. 287 | localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) 288 | 289 | if ctx != nil { 290 | // add context to the request 291 | localVarRequest = localVarRequest.WithContext(ctx) 292 | } 293 | 294 | // Walk through any authentication. 295 | auth := c.cfg.Authentication 296 | if auth.OAuth2 != nil { 297 | // OAuth2 authentication 298 | var latestToken *oauth2.Token 299 | if latestToken, err = (*auth.OAuth2).Token(); err != nil { 300 | return nil, err 301 | } 302 | 303 | latestToken.SetAuthHeader(localVarRequest) 304 | } 305 | 306 | if auth.BasicAuth != nil { 307 | // Basic HTTP Authentication 308 | localVarRequest.SetBasicAuth(auth.BasicAuth.UserName, auth.BasicAuth.Password) 309 | } 310 | 311 | if auth.AccessToken != nil { 312 | // AccessToken Authentication 313 | localVarRequest.Header.Add("Authorization", "Bearer "+*auth.AccessToken) 314 | } 315 | 316 | for header, value := range c.cfg.DefaultHeader { 317 | localVarRequest.Header.Add(header, value) 318 | } 319 | 320 | return localVarRequest, nil 321 | } 322 | 323 | func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { 324 | if strings.Contains(contentType, "application/xml") { 325 | if err = xml.Unmarshal(b, v); err != nil { 326 | return err 327 | } 328 | return nil 329 | } else if strings.Contains(contentType, "application/json") { 330 | if err = json.Unmarshal(b, v); err != nil { 331 | return err 332 | } 333 | return nil 334 | } 335 | return errors.New("undefined response type") 336 | } 337 | 338 | // Add a file to the multipart request 339 | func addFile(w *multipart.Writer, fieldName, path string) error { 340 | file, err := os.Open(path) 341 | if err != nil { 342 | return err 343 | } 344 | defer file.Close() 345 | 346 | part, err := w.CreateFormFile(fieldName, filepath.Base(path)) 347 | if err != nil { 348 | return err 349 | } 350 | _, err = io.Copy(part, file) 351 | 352 | return err 353 | } 354 | 355 | // Prevent trying to import "fmt" 356 | func reportError(format string, a ...interface{}) error { 357 | return fmt.Errorf(format, a...) 358 | } 359 | 360 | // Set request body from an interface{} 361 | func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { 362 | if bodyBuf == nil { 363 | bodyBuf = &bytes.Buffer{} 364 | } 365 | 366 | if reader, ok := body.(io.Reader); ok { 367 | _, err = bodyBuf.ReadFrom(reader) 368 | } else if b, ok := body.([]byte); ok { 369 | _, err = bodyBuf.Write(b) 370 | } else if s, ok := body.(string); ok { 371 | _, err = bodyBuf.WriteString(s) 372 | } else if s, ok := body.(*string); ok { 373 | _, err = bodyBuf.WriteString(*s) 374 | } else if jsonCheck.MatchString(contentType) { 375 | err = json.NewEncoder(bodyBuf).Encode(body) 376 | } else if xmlCheck.MatchString(contentType) { 377 | xml.NewEncoder(bodyBuf).Encode(body) 378 | } 379 | 380 | if err != nil { 381 | return nil, err 382 | } 383 | 384 | if bodyBuf.Len() == 0 { 385 | err = fmt.Errorf("Invalid body type %s\n", contentType) 386 | return nil, err 387 | } 388 | return bodyBuf, nil 389 | } 390 | 391 | // detectContentType method is used to figure out `Request.Body` content type for request header 392 | func detectContentType(body interface{}) string { 393 | contentType := "text/plain; charset=utf-8" 394 | kind := reflect.TypeOf(body).Kind() 395 | 396 | switch kind { 397 | case reflect.Struct, reflect.Map, reflect.Ptr: 398 | contentType = "application/json; charset=utf-8" 399 | case reflect.String: 400 | contentType = "text/plain; charset=utf-8" 401 | default: 402 | if b, ok := body.([]byte); ok { 403 | contentType = http.DetectContentType(b) 404 | } else if kind == reflect.Slice { 405 | contentType = "application/json; charset=utf-8" 406 | } 407 | } 408 | 409 | return contentType 410 | } 411 | 412 | // Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go 413 | type cacheControl map[string]string 414 | 415 | func parseCacheControl(headers http.Header) cacheControl { 416 | cc := cacheControl{} 417 | ccHeader := headers.Get("Cache-Control") 418 | for _, part := range strings.Split(ccHeader, ",") { 419 | part = strings.Trim(part, " ") 420 | if part == "" { 421 | continue 422 | } 423 | if strings.ContainsRune(part, '=') { 424 | keyval := strings.Split(part, "=") 425 | cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") 426 | } else { 427 | cc[part] = "" 428 | } 429 | } 430 | return cc 431 | } 432 | 433 | // CacheExpires helper function to determine remaining time before repeating a request. 434 | func CacheExpires(r *http.Response) time.Time { 435 | // Figure out when the cache expires. 436 | var expires time.Time 437 | now, err := time.Parse(time.RFC1123, r.Header.Get("date")) 438 | if err != nil { 439 | return time.Now() 440 | } 441 | respCacheControl := parseCacheControl(r.Header) 442 | 443 | if maxAge, ok := respCacheControl["max-age"]; ok { 444 | lifetime, err := time.ParseDuration(maxAge + "s") 445 | if err != nil { 446 | expires = now 447 | } else { 448 | expires = now.Add(lifetime) 449 | } 450 | } else { 451 | expiresHeader := r.Header.Get("Expires") 452 | if expiresHeader != "" { 453 | expires, err = time.Parse(time.RFC1123, expiresHeader) 454 | if err != nil { 455 | expires = now 456 | } 457 | } 458 | } 459 | return expires 460 | } 461 | 462 | func strlen(s string) int { 463 | return utf8.RuneCountInString(s) 464 | } 465 | 466 | // ApproveApiError Provides access to the body, error and model on returned errors. 467 | type ApproveApiError struct { 468 | body []byte 469 | error string 470 | model interface{} 471 | } 472 | 473 | // Error returns non-empty string if there was an error. 474 | func (e ApproveApiError) Error() string { 475 | return e.error 476 | } 477 | 478 | // Body returns the raw bytes of the response 479 | func (e ApproveApiError) Body() []byte { 480 | return e.body 481 | } 482 | 483 | // Model returns the unpacked model of the error 484 | func (e ApproveApiError) Model() interface{} { 485 | return e.model 486 | } 487 | -------------------------------------------------------------------------------- /configuration.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | import ( 14 | "net/http" 15 | 16 | "golang.org/x/oauth2" 17 | ) 18 | 19 | // BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth 20 | type BasicAuth struct { 21 | UserName string `json:"userName,omitempty"` 22 | Password string `json:"password,omitempty"` 23 | } 24 | 25 | // APIKey provides API key based authentication to a request passed via context using ContextAPIKey 26 | type APIKey struct { 27 | Key string 28 | Prefix string 29 | } 30 | 31 | type Authentication struct { 32 | APIKey *APIKey 33 | BasicAuth *BasicAuth 34 | OAuth2 *oauth2.TokenSource 35 | AccessToken *string 36 | } 37 | 38 | type Configuration struct { 39 | BasePath string `json:"basePath,omitempty"` 40 | Host string `json:"host,omitempty"` 41 | Scheme string `json:"scheme,omitempty"` 42 | DefaultHeader map[string]string `json:"defaultHeader,omitempty"` 43 | UserAgent string `json:"userAgent,omitempty"` 44 | Authentication Authentication `json:"authentication,omitempty"` 45 | HTTPClient *http.Client 46 | } 47 | 48 | func NewConfiguration() *Configuration { 49 | cfg := &Configuration{ 50 | BasePath: "https://approve.sh", 51 | DefaultHeader: make(map[string]string), 52 | UserAgent: "OpenAPI-Generator/1.0.5/go", 53 | } 54 | return cfg 55 | } 56 | 57 | func (c *Configuration) AddDefaultHeader(key string, value string) { 58 | c.DefaultHeader[key] = value 59 | } 60 | -------------------------------------------------------------------------------- /docs/AnswerMetadata.md: -------------------------------------------------------------------------------- 1 | # AnswerMetadata 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **SlackRealName** | **string** | | [optional] 7 | **OperatingSystem** | **string** | | [optional] 8 | **SlackUsername** | **string** | | [optional] 9 | **IpAddress** | **string** | | [optional] 10 | **SlackEmail** | **string** | | [optional] 11 | **Browser** | **string** | | [optional] 12 | 13 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/ApproveApi.md: -------------------------------------------------------------------------------- 1 | # \ApproveApi 2 | 3 | All URIs are relative to *https://approve.sh* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**CreatePrompt**](ApproveApi.md#CreatePrompt) | **Post** /prompt | Sending a prompt 8 | [**GetPrompt**](ApproveApi.md#GetPrompt) | **Get** /prompt/{id} | Retrieve a prompt 9 | [**GetPromptStatus**](ApproveApi.md#GetPromptStatus) | **Get** /prompt/{id}/status | Check prompt status 10 | 11 | 12 | # **CreatePrompt** 13 | > Prompt CreatePrompt(ctx, createPromptRequest) 14 | Sending a prompt 15 | 16 | Creates a prompt and pushes it to the user (sends via email, sms, or other supported protocols). 17 | 18 | ### Required Parameters 19 | 20 | Name | Type | Description | Notes 21 | ------------- | ------------- | ------------- | ------------- 22 | **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. 23 | **createPromptRequest** | [**CreatePromptRequest**](CreatePromptRequest.md)| | 24 | 25 | ### Return type 26 | 27 | [**Prompt**](Prompt.md) 28 | 29 | ### Authorization 30 | 31 | [apiKey](../README.md#apiKey) 32 | 33 | ### HTTP request headers 34 | 35 | - **Content-Type**: application/json 36 | - **Accept**: application/json 37 | 38 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 39 | 40 | # **GetPrompt** 41 | > Prompt GetPrompt(ctx, id, optional) 42 | Retrieve a prompt 43 | 44 | Retrieve the prompt object with the given ID. 45 | 46 | ### Required Parameters 47 | 48 | Name | Type | Description | Notes 49 | ------------- | ------------- | ------------- | ------------- 50 | **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. 51 | **id** | **string**| The identifier for a pending or completed prompt. This is returned when you create a prompt. | 52 | **optional** | ***GetPromptOpts** | optional parameters | nil if no parameters 53 | 54 | ### Optional Parameters 55 | Optional parameters are passed through a pointer to a GetPromptOpts struct 56 | 57 | Name | Type | Description | Notes 58 | ------------- | ------------- | ------------- | ------------- 59 | 60 | **longPoll** | **optional.Bool**| If true, the request waits (long-polls) until the user responds to the prompt or more than 10 minutes pass. Defaults to false. | 61 | 62 | ### Return type 63 | 64 | [**Prompt**](Prompt.md) 65 | 66 | ### Authorization 67 | 68 | [apiKey](../README.md#apiKey) 69 | 70 | ### HTTP request headers 71 | 72 | - **Content-Type**: Not defined 73 | - **Accept**: application/json 74 | 75 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 76 | 77 | # **GetPromptStatus** 78 | > PromptStatus GetPromptStatus(ctx, id) 79 | Check prompt status 80 | 81 | Returns whether a prompt has been completed by the user. This request does not require authentication, and so can be used client-side without sharing API credentials. 82 | 83 | ### Required Parameters 84 | 85 | Name | Type | Description | Notes 86 | ------------- | ------------- | ------------- | ------------- 87 | **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. 88 | **id** | **string**| The prompt identifier. | 89 | 90 | ### Return type 91 | 92 | [**PromptStatus**](PromptStatus.md) 93 | 94 | ### Authorization 95 | 96 | No authorization required 97 | 98 | ### HTTP request headers 99 | 100 | - **Content-Type**: Not defined 101 | - **Accept**: application/json 102 | 103 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) 104 | 105 | -------------------------------------------------------------------------------- /docs/CreatePromptRequest.md: -------------------------------------------------------------------------------- 1 | # CreatePromptRequest 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **Body** | **string** | The body of the approval request to show the user. | 7 | **IdempotencyKey** | **string** | Allows calling `create_prompt` multiple times idempotently, such that a prompt is sent at-most once. This key should contain sufficient randomness. Idempotent requests are stored for 24 hours. After that time, the same key will create a new request. | [optional] 8 | **Title** | **string** | The title of an approval request. Defaults to an empty string. | [optional] 9 | **RejectText** | **string** | The reject action text. If not specified the reject button will NOT be rendered, and the user will only see an approve action button. | [optional] 10 | **ExpiresIn** | **float32** | The number of seconds until this request can no longer be answered. | [optional] 11 | **LongPoll** | **bool** | If true, the request waits (long-polls) until the user responds to the prompt or more than 10 minutes pass. Defaults to false. | [optional] 12 | **InternalData** | **map[string]string** | | [optional] 13 | **User** | **string** | The user to send the approval request to. Can be either an email address or a phone number. | 14 | **ApproveText** | **string** | The approve action text. Defaults to 'Approve'. | [optional] 15 | **ApproveRedirectUrl** | **string** | An HTTPS URL to redirect the user to if the prompt is approved. This URL is kept secret until the user is redirected to it. | [optional] 16 | **RejectRedirectUrl** | **string** | An HTTPS URL to redirect the user to if the prompt is rejected. This URL is kept secret until the user is redirected to it. | [optional] 17 | **Metadata** | [**PromptMetadata**](PromptMetadata.md) | | [optional] 18 | 19 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/Error.md: -------------------------------------------------------------------------------- 1 | # Error 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **Error** | **string** | A human readable API error message. | 7 | 8 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/Prompt.md: -------------------------------------------------------------------------------- 1 | # Prompt 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **SentAt** | **float32** | The unix timestamp when this prompt was sent. | 7 | **Answer** | [**PromptAnswer**](PromptAnswer.md) | | [optional] 8 | **IsExpired** | **bool** | Whether the prompt can still be answered. | 9 | **Request** | [**CreatePromptRequest**](CreatePromptRequest.md) | | 10 | **Id** | **string** | A unique id for this prompt. | 11 | **Metadata** | [**PromptMetadata**](PromptMetadata.md) | | [optional] 12 | 13 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/PromptAnswer.md: -------------------------------------------------------------------------------- 1 | # PromptAnswer 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **Time** | **float32** | The unix timestamp when the user answered the prompt. | 7 | **Result** | **bool** | The user's answer to whether or not they approve this prompt. | 8 | **Metadata** | [**AnswerMetadata**](AnswerMetadata.md) | | [optional] 9 | 10 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/PromptMetadata.md: -------------------------------------------------------------------------------- 1 | # PromptMetadata 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **Time** | **string** | The date/time of the action. | [optional] 7 | **OperatingSystem** | **string** | The operating system initiating the action, i.e. Mac OS X. | [optional] 8 | **IpAddress** | **string** | The IP address of the computer initiating the action. | [optional] 9 | **Location** | **string** | The physical location, like Oakland, CA, of the action. | [optional] 10 | **Browser** | **string** | The web browser initiating the action, i.e. Chrome. | [optional] 11 | 12 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/PromptStatus.md: -------------------------------------------------------------------------------- 1 | # PromptStatus 2 | 3 | ## Properties 4 | Name | Type | Description | Notes 5 | ------------ | ------------- | ------------- | ------------- 6 | **IsAnswered** | **bool** | Whether the prompt has been answered or not. | 7 | **IsExpired** | **bool** | Whether the prompt can still be answered. | 8 | 9 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 10 | 11 | 12 | -------------------------------------------------------------------------------- /git_push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ 3 | # 4 | # Usage example: /bin/sh ./git_push.sh wing328 openapi-pestore-perl "minor update" 5 | 6 | git_user_id=$1 7 | git_repo_id=$2 8 | release_note=$3 9 | 10 | if [ "$git_user_id" = "" ]; then 11 | git_user_id="GIT_USER_ID" 12 | echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" 13 | fi 14 | 15 | if [ "$git_repo_id" = "" ]; then 16 | git_repo_id="GIT_REPO_ID" 17 | echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" 18 | fi 19 | 20 | if [ "$release_note" = "" ]; then 21 | release_note="Minor update" 22 | echo "[INFO] No command line input provided. Set \$release_note to $release_note" 23 | fi 24 | 25 | # Initialize the local directory as a Git repository 26 | git init 27 | 28 | # Adds the files in the local repository and stages them for commit. 29 | git add . 30 | 31 | # Commits the tracked changes and prepares them to be pushed to a remote repository. 32 | git commit -m "$release_note" 33 | 34 | # Sets the new remote 35 | git_remote=`git remote` 36 | if [ "$git_remote" = "" ]; then # git remote not defined 37 | 38 | if [ "$GIT_TOKEN" = "" ]; then 39 | echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." 40 | git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git 41 | else 42 | git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git 43 | fi 44 | 45 | fi 46 | 47 | git pull origin master 48 | 49 | # Pushes (Forces) the changes in the local repository up to the remote repository 50 | echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" 51 | git push origin master 2>&1 | grep -v 'To https' 52 | 53 | -------------------------------------------------------------------------------- /model_answer_metadata.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | type AnswerMetadata struct { 14 | SlackRealName *string `json:"slack_real_name,omitempty"` 15 | OperatingSystem *string `json:"operating_system,omitempty"` 16 | SlackUsername *string `json:"slack_username,omitempty"` 17 | IpAddress *string `json:"ip_address,omitempty"` 18 | SlackEmail *string `json:"slack_email,omitempty"` 19 | Browser *string `json:"browser,omitempty"` 20 | } 21 | -------------------------------------------------------------------------------- /model_create_prompt_request.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | type CreatePromptRequest struct { 14 | // The body of the approval request to show the user. 15 | Body string `json:"body"` 16 | // Allows calling `create_prompt` multiple times idempotently, such that a prompt is sent at-most once. This key should contain sufficient randomness. Idempotent requests are stored for 24 hours. After that time, the same key will create a new request. 17 | IdempotencyKey *string `json:"idempotency_key,omitempty"` 18 | // The title of an approval request. Defaults to an empty string. 19 | Title *string `json:"title,omitempty"` 20 | // The reject action text. If not specified the reject button will NOT be rendered, and the user will only see an approve action button. 21 | RejectText *string `json:"reject_text,omitempty"` 22 | // The number of seconds until this request can no longer be answered. 23 | ExpiresIn *float32 `json:"expires_in,omitempty"` 24 | // If true, the request waits (long-polls) until the user responds to the prompt or more than 10 minutes pass. Defaults to false. 25 | LongPoll *bool `json:"long_poll,omitempty"` 26 | InternalData *map[string]string `json:"internal_data,omitempty"` 27 | // The user to send the approval request to. Can be either an email address or a phone number. 28 | User string `json:"user"` 29 | // The approve action text. Defaults to 'Approve'. 30 | ApproveText *string `json:"approve_text,omitempty"` 31 | // An HTTPS URL to redirect the user to if the prompt is approved. This URL is kept secret until the user is redirected to it. 32 | ApproveRedirectUrl *string `json:"approve_redirect_url,omitempty"` 33 | // An HTTPS URL to redirect the user to if the prompt is rejected. This URL is kept secret until the user is redirected to it. 34 | RejectRedirectUrl *string `json:"reject_redirect_url,omitempty"` 35 | Metadata *PromptMetadata `json:"metadata,omitempty"` 36 | } 37 | -------------------------------------------------------------------------------- /model_error.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | type Error struct { 14 | // A human readable API error message. 15 | Error string `json:"error"` 16 | } 17 | -------------------------------------------------------------------------------- /model_prompt.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | type Prompt struct { 14 | // The unix timestamp when this prompt was sent. 15 | SentAt float32 `json:"sent_at"` 16 | Answer *PromptAnswer `json:"answer,omitempty"` 17 | // Whether the prompt can still be answered. 18 | IsExpired bool `json:"is_expired"` 19 | Request CreatePromptRequest `json:"request"` 20 | // A unique id for this prompt. 21 | Id string `json:"id"` 22 | Metadata *PromptMetadata `json:"metadata,omitempty"` 23 | } 24 | -------------------------------------------------------------------------------- /model_prompt_answer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | type PromptAnswer struct { 14 | // The unix timestamp when the user answered the prompt. 15 | Time float32 `json:"time"` 16 | // The user's answer to whether or not they approve this prompt. 17 | Result bool `json:"result"` 18 | Metadata *AnswerMetadata `json:"metadata,omitempty"` 19 | } 20 | -------------------------------------------------------------------------------- /model_prompt_metadata.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | type PromptMetadata struct { 14 | // The date/time of the action. 15 | Time *string `json:"time,omitempty"` 16 | // The operating system initiating the action, i.e. Mac OS X. 17 | OperatingSystem *string `json:"operating_system,omitempty"` 18 | // The IP address of the computer initiating the action. 19 | IpAddress *string `json:"ip_address,omitempty"` 20 | // The physical location, like Oakland, CA, of the action. 21 | Location *string `json:"location,omitempty"` 22 | // The web browser initiating the action, i.e. Chrome. 23 | Browser *string `json:"browser,omitempty"` 24 | } 25 | -------------------------------------------------------------------------------- /model_prompt_status.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | type PromptStatus struct { 14 | // Whether the prompt has been answered or not. 15 | IsAnswered bool `json:"is_answered"` 16 | // Whether the prompt can still be answered. 17 | IsExpired bool `json:"is_expired"` 18 | } 19 | -------------------------------------------------------------------------------- /response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * ApproveAPISwagger 3 | * 4 | * The simple API to request a user's approval on anything via email + sms. 5 | * 6 | * API version: 1.0.1 7 | * Contact: dev@approveapi.com 8 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 9 | */ 10 | 11 | package approveapi 12 | 13 | import ( 14 | "net/http" 15 | ) 16 | 17 | type APIResponse struct { 18 | *http.Response `json:"-"` 19 | Message string `json:"message,omitempty"` 20 | // Operation is the name of the OpenAPI operation. 21 | Operation string `json:"operation,omitempty"` 22 | // RequestURL is the request URL. This value is always available, even if the 23 | // embedded *http.Response is nil. 24 | RequestURL string `json:"url,omitempty"` 25 | // Method is the HTTP method used for the request. This value is always 26 | // available, even if the embedded *http.Response is nil. 27 | Method string `json:"method,omitempty"` 28 | // Payload holds the contents of the response body (which may be nil or empty). 29 | // This is provided here as the raw response.Body() reader will have already 30 | // been drained. 31 | Payload []byte `json:"-"` 32 | } 33 | 34 | func NewAPIResponse(r *http.Response) *APIResponse { 35 | 36 | response := &APIResponse{Response: r} 37 | return response 38 | } 39 | 40 | func NewAPIResponseWithError(errorMessage string) *APIResponse { 41 | 42 | response := &APIResponse{Message: errorMessage} 43 | return response 44 | } 45 | --------------------------------------------------------------------------------