{
  "openapi": "3.1.0",
  "info": {
    "title": "WAutomate API",
    "version": "1.0.0",
    "description": "REST API for the WAutomate WhatsApp Business platform.\n\nAll requests are authenticated with an API key issued from your dashboard (Settings -> API Keys) and sent as a bearer token.\n\nRate limits are per API key, per minute (60/min by default). Any POST accepts an `Idempotency-Key` header; use it on anything that spends money.\n\nOutbound webhooks are configured in the dashboard and are signed with `X-WAutomate-Signature: sha256=<hmac>` over the raw body.",
    "contact": {
      "name": "WAutomate",
      "url": "https://wautomate.in/docs/api"
    }
  },
  "servers": [
    {
      "url": "https://wautomate.in/api/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Messaging",
      "description": "Send messages, templates and campaigns"
    },
    {
      "name": "Contacts",
      "description": "Read and write contacts and their custom attributes"
    },
    {
      "name": "Account",
      "description": "Wallet balance and usage"
    },
    {
      "name": "Campaigns",
      "description": "Campaign results"
    },
    {
      "name": "Templates",
      "description": "Meta message templates"
    },
    {
      "name": "Media",
      "description": "Upload media for template headers"
    },
    {
      "name": "Partner",
      "description": "Reseller provisioning (requires a partner-enabled key)"
    }
  ],
  "paths": {
    "/send-template": {
      "post": {
        "tags": [
          "Messaging"
        ],
        "summary": "Send a template message",
        "description": "Sends a Meta-approved template. Supports image, video and document headers.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string",
                    "example": "919876543210"
                  },
                  "template": {
                    "type": "string",
                    "example": "invoice_paid"
                  },
                  "language": {
                    "type": "string",
                    "pattern": "^[a-z]{2,3}(_[A-Z]{2})?$",
                    "example": "en_US",
                    "description": "The template's language code \u2014 'en' or 'en_US'. Must match the template exactly; most templates are en_US."
                  },
                  "variables": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "header_media_type": {
                    "type": "string",
                    "enum": [
                      "image",
                      "video",
                      "document"
                    ]
                  },
                  "header_media_url": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  }
                },
                "required": [
                  "phone",
                  "template",
                  "language"
                ]
              }
            }
          }
        }
      }
    },
    "/send-message": {
      "post": {
        "tags": [
          "Messaging"
        ],
        "summary": "Send a message (text, media or reply buttons)",
        "description": "Text, images, video, documents, audio and reply buttons - the same things a chatbot flow can send. Only deliverable inside an open 24-hour customer service window; outside it use /send-template. Reply buttons cannot be attached to a media message (a WhatsApp limit) - that returns 422 rather than dropping them silently.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone"
                ],
                "properties": {
                  "phone": {
                    "type": "string",
                    "example": "919876543210"
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 4096,
                    "description": "Required unless sending media, where the words go in caption."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "text",
                      "image",
                      "video",
                      "document",
                      "audio"
                    ],
                    "default": "text"
                  },
                  "media_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Public URL of the file. Use this or media_id."
                  },
                  "media_id": {
                    "type": "string",
                    "description": "Media id returned by POST /public/media. Valid 30 days."
                  },
                  "caption": {
                    "type": "string",
                    "maxLength": 1024
                  },
                  "filename": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "The name the recipient sees for a document."
                  },
                  "buttons": {
                    "type": "array",
                    "maxItems": 3,
                    "items": {
                      "type": "object",
                      "required": [
                        "id",
                        "title"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "maxLength": 256
                        },
                        "title": {
                          "type": "string",
                          "maxLength": 20
                        }
                      }
                    },
                    "description": "Reply buttons. Text messages only. The tapped id comes back on the message.inbound webhook."
                  }
                }
              },
              "examples": {
                "text": {
                  "summary": "Plain text",
                  "value": {
                    "phone": "919876543210",
                    "message": "Hello! Your agent is now online."
                  }
                },
                "image": {
                  "summary": "Image with a caption",
                  "value": {
                    "phone": "919876543210",
                    "type": "image",
                    "media_url": "https://yoursite.in/order.jpg",
                    "caption": "Your order has shipped"
                  }
                },
                "document": {
                  "summary": "PDF by media_id",
                  "value": {
                    "phone": "919876543210",
                    "type": "document",
                    "media_id": "1234567890",
                    "filename": "Invoice_INV-2231.pdf",
                    "caption": "Your invoice is attached."
                  }
                },
                "video": {
                  "summary": "Video",
                  "value": {
                    "phone": "919876543210",
                    "type": "video",
                    "media_url": "https://yoursite.in/demo.mp4",
                    "caption": "60-second walkthrough"
                  }
                },
                "buttons": {
                  "summary": "Reply buttons",
                  "value": {
                    "phone": "919876543210",
                    "message": "Did that solve your problem?",
                    "buttons": [
                      {
                        "id": "yes",
                        "title": "Yes, thanks"
                      },
                      {
                        "id": "no",
                        "title": "Not really"
                      },
                      {
                        "id": "agent",
                        "title": "Talk to a person"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Queued"
          },
          "422": {
            "description": "Validation failed - buttons on a media message, more than 3 buttons, or a title over 20 characters"
          }
        }
      }
    },
    "/send-campaign": {
      "post": {
        "tags": [
          "Messaging"
        ],
        "summary": "Trigger an existing campaign",
        "description": "Starts a campaign that was already created in the dashboard.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "integer"
                  }
                },
                "required": [
                  "campaign_id"
                ]
              }
            }
          }
        }
      }
    },
    "/campaigns/create-with-csv": {
      "post": {
        "tags": [
          "Messaging"
        ],
        "summary": "Create a campaign from a CSV",
        "description": "multipart/form-data. Creates the campaign and its recipient list in one call.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/create-contact": {
      "post": {
        "tags": [
          "Messaging"
        ],
        "summary": "Create a contact",
        "description": "Creates a contact, or returns the existing one with the same phone number.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "custom_attributes": {
                    "type": "object"
                  }
                },
                "required": [
                  "phone",
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/conversations/{phone}": {
      "get": {
        "tags": [
          "Messaging"
        ],
        "summary": "List conversations for a number",
        "description": "",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Phone number in international format"
          }
        ]
      }
    },
    "/messages/{conversationId}": {
      "get": {
        "tags": [
          "Messaging"
        ],
        "summary": "List messages in a conversation",
        "description": "",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "conversationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    },
    "/message-status/{id}": {
      "get": {
        "tags": [
          "Messaging"
        ],
        "summary": "Check message status",
        "description": "Returns queued, sent, delivered, read or failed.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    },
    "/public/balance": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get wallet balance",
        "description": "Read your balance before starting a large run.",
        "responses": {
          "200": {
            "description": "Balance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "balance": {
                      "type": "number"
                    },
                    "currency": {
                      "type": "string"
                    },
                    "low_balance_threshold": {
                      "type": "number"
                    },
                    "is_low": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/public/usage": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get usage and spend",
        "description": "Defaults to the current month. Totals come from the billing ledger.",
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "from": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    },
                    "currency": {
                      "type": "string"
                    },
                    "billed_messages": {
                      "type": "integer"
                    },
                    "spend": {
                      "type": "number"
                    },
                    "refunded": {
                      "type": "number"
                    },
                    "net_spend": {
                      "type": "number"
                    },
                    "by_conversation_type": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO date, inclusive"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO date, inclusive"
          }
        ]
      }
    },
    "/public/contacts": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts",
        "description": "",
        "responses": {
          "200": {
            "description": "Contacts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "contacts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contact"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "per_page": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "total_pages": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "phone",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Max 200"
          }
        ]
      }
    },
    "/public/contacts/{id}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact",
        "description": "Includes every custom attribute.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      },
      "put": {
        "tags": [
          "Contacts"
        ],
        "summary": "Update a contact",
        "description": "",
        "responses": {
          "200": {
            "description": "Updated"
          },
          "409": {
            "description": "Another contact already has this phone number"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "opt_in": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete a contact",
        "description": "Soft delete.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    },
    "/public/contacts/{id}/attributes": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get custom attributes",
        "description": "",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      },
      "put": {
        "tags": [
          "Contacts"
        ],
        "summary": "Merge custom attributes",
        "description": "Keys are normalised the way the flow engine normalises them: \"Order ID\" is stored as order_id and read inside a flow as {{attr.order_id}}. Existing keys are kept unless overwritten.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "attributes": {
                    "type": "object"
                  }
                },
                "required": [
                  "attributes"
                ]
              }
            }
          }
        }
      }
    },
    "/public/contacts/{id}/attributes/{key}": {
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete one attribute",
        "description": "",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          },
          {
            "name": "key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Attribute key"
          }
        ]
      }
    },
    "/public/campaigns": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "List campaigns",
        "description": "",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Max 100"
          }
        ]
      }
    },
    "/public/campaigns/{id}/stats": {
      "get": {
        "tags": [
          "Campaigns"
        ],
        "summary": "Campaign results",
        "description": "Sent, delivered, read and failed counts.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    },
    "/public/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "List templates",
        "description": "Add ?all=1 to include pending and rejected.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "all",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          }
        ]
      },
      "post": {
        "tags": [
          "Templates"
        ],
        "summary": "Create a template",
        "description": "multipart/form-data. Submits to Meta; the template comes back with status PENDING. Send header_file to attach an image, video or document header sample.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/public/templates/sync": {
      "post": {
        "tags": [
          "Templates"
        ],
        "summary": "Sync approval status from Meta",
        "description": "",
        "responses": {
          "200": {
            "description": "Success"
          }
        }
      }
    },
    "/public/templates/{id}": {
      "delete": {
        "tags": [
          "Templates"
        ],
        "summary": "Delete a template",
        "description": "Removes it from Meta and from your account.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    },
    "/public/media": {
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Upload media",
        "description": "multipart/form-data, field `file`, max 100 MB. Returns a Meta media_id (valid 30 days). Gupshup-hosted numbers get a media_url instead \u2014 use whichever field is non-null.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        }
      }
    },
    "/public/partner/tenants": {
      "get": {
        "tags": [
          "Partner"
        ],
        "summary": "List your client workspaces",
        "description": "Requires an API key with partner provisioning enabled; an ordinary key gets 403.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Max 100"
          }
        ]
      },
      "post": {
        "tags": [
          "Partner"
        ],
        "summary": "Provision a client workspace",
        "description": "Requires an API key with partner provisioning enabled; an ordinary key gets 403. Creates the workspace, its owner login and (unless create_api_key is false) its API key. The key and any generated password are returned exactly once.",
        "responses": {
          "201": {
            "description": "Created"
          },
          "402": {
            "description": "Insufficient partner balance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Key is not partner-enabled",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "company_name": {
                    "type": "string"
                  },
                  "owner_name": {
                    "type": "string"
                  },
                  "owner_email": {
                    "type": "string",
                    "format": "email"
                  },
                  "owner_password": {
                    "type": "string",
                    "description": "Optional. One is generated if omitted."
                  },
                  "credits": {
                    "type": "number",
                    "description": "Moved from your balance at creation time."
                  },
                  "create_api_key": {
                    "type": "boolean",
                    "default": true
                  }
                },
                "required": [
                  "company_name",
                  "owner_name",
                  "owner_email"
                ]
              }
            }
          }
        }
      }
    },
    "/public/partner/tenants/{id}": {
      "get": {
        "tags": [
          "Partner"
        ],
        "summary": "Get a client workspace",
        "description": "Requires an API key with partner provisioning enabled; an ordinary key gets 403.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    },
    "/public/partner/tenants/{id}/credits": {
      "post": {
        "tags": [
          "Partner"
        ],
        "summary": "Allocate credits",
        "description": "Requires an API key with partner provisioning enabled; an ordinary key gets 403. Moves balance from you to the client.",
        "responses": {
          "200": {
            "description": "Allocated"
          },
          "402": {
            "description": "Insufficient partner balance"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "credits": {
                    "type": "number"
                  }
                },
                "required": [
                  "credits"
                ]
              }
            }
          }
        }
      }
    },
    "/public/partner/tenants/{id}/api-keys": {
      "post": {
        "tags": [
          "Partner"
        ],
        "summary": "Issue an API key for a client",
        "description": "Requires an API key with partner provisioning enabled; an ordinary key gets 403. Returned once.",
        "responses": {
          "201": {
            "description": "Created"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ]
      }
    },
    "/public/partner/tenants/{id}/suspend": {
      "post": {
        "tags": [
          "Partner"
        ],
        "summary": "Suspend a client",
        "description": "Requires an API key with partner provisioning enabled; an ordinary key gets 403. Suspends their API keys. Data is kept.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    },
    "/public/partner/tenants/{id}/activate": {
      "post": {
        "tags": [
          "Partner"
        ],
        "summary": "Reactivate a client",
        "description": "Requires an API key with partner provisioning enabled; an ordinary key gets 403.",
        "responses": {
          "200": {
            "description": "Success"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Resource id"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your API key from Settings -> API Keys, sent as `Authorization: Bearer ra_...`"
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 255
        },
        "description": "Makes a retry safe. The first response for a given key is replayed for 24 hours and marked with `Idempotency-Replayed: true`. Reusing a key with a different body returns 422. Scoped to your API key."
      }
    },
    "schemas": {
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "opt_in": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        }
      }
    }
  }
}
