{
  "openapi": "3.1.0",
  "info": {
    "title": "PIP Links API",
    "version": "1.0.0 (PIP Links 4.42.0)",
    "description": "Make campaigns, tracked QR codes and short links, and clients in a PIP Links account, and read the results. Exclusively for PIP centers."
  },
  "servers": [
    {
      "url": "https://api.pipic.link"
    }
  ],
  "security": [
    {
      "key": []
    }
  ],
  "components": {
    "securitySchemes": {
      "key": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from Settings → API keys (pl_live_…)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "limit": {
            "type": "object"
          }
        },
        "required": [
          "error",
          "message"
        ]
      }
    }
  },
  "paths": {
    "/v1/account": {
      "get": {
        "summary": "This key, its account and plan, codes made this month and what's left, extra codes (Enterprise) and the key's rate limits",
        "description": "This key, its account and plan, codes made this month and what's left, extra codes (Enterprise) and the key's rate limits. Check it before a big batch.",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "account": {
                    "id": "pip-iowa-city",
                    "name": "PIP Iowa City",
                    "plan": "pro",
                    "plan_name": "Pro",
                    "short_host": "pipic.link"
                  },
                  "key": {
                    "id": "k3x9…",
                    "name": "PIP Intelligence",
                    "prefix": "pl_live_Ab3d",
                    "scopes": [
                      "campaigns:read",
                      "codes:write"
                    ],
                    "client_id": null
                  },
                  "codes": {
                    "this_month": 1200,
                    "plan_limit": 100000,
                    "left_this_month": 98800,
                    "resets_at": "2026-11-01T00:00:00.000Z",
                    "extra": null
                  },
                  "rate_limits": {
                    "requests_per_minute": 300,
                    "rows_per_batch": 5000
                  }
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/clients": {
      "get": {
        "summary": "The account's clients (brands)",
        "description": "The account's clients (brands). Your own brand is marked own_brand.",
        "tags": [
          "Clients"
        ],
        "x-scope": "clients:read",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "clients": [
                    {
                      "id": "pip-iowa-city",
                      "name": "PIP Iowa City",
                      "color": "#002d61",
                      "website": "https://pipic.com/",
                      "short_host": null,
                      "own_brand": true
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Add a client",
        "description": "Add a client. Counts against the plan's clients.",
        "tags": [
          "Clients"
        ],
        "x-scope": "clients:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The client's name."
                  },
                  "id": {
                    "type": "string",
                    "description": "Lowercase letters, numbers and dashes (made from the name if left out)."
                  },
                  "color": {
                    "type": "string",
                    "description": "Brand color, like #0f6fa3."
                  },
                  "website": {
                    "type": "string",
                    "description": "Their web address."
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "client": {
                    "id": "lakeside-dental",
                    "name": "Lakeside Dental",
                    "color": "#0f6fa3",
                    "website": null,
                    "short_host": null,
                    "own_brand": false
                  }
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns": {
      "get": {
        "summary": "Mailing campaigns, newest first",
        "description": "Mailing campaigns, newest first.",
        "tags": [
          "Campaigns"
        ],
        "x-scope": "campaigns:read",
        "parameters": [
          {
            "name": "client_id",
            "in": "query",
            "required": false,
            "description": "Only this client's.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_ref",
            "in": "query",
            "required": false,
            "description": "Only the campaign with this external_ref.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "active (default), archived or all.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "campaigns": [
                    {
                      "id": "spring-tune-up",
                      "name": "Spring tune-up",
                      "client_id": "lakeside-dental",
                      "external_ref": "N208057",
                      "destination": "https://example.com/spring",
                      "mail_date": "2026-11-02",
                      "codes": 2000,
                      "archived": false,
                      "source": "api:PIP Intelligence"
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Make a campaign",
        "description": "Make a campaign. With an external_ref (a PressWise order number, an InDesign document ID), posting the same one again returns the campaign you already made (created: false) instead of a second one.",
        "tags": [
          "Campaigns"
        ],
        "x-scope": "campaigns:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "destination"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "What to call it."
                  },
                  "destination": {
                    "type": "string",
                    "description": "The web address its codes open (change it any time)."
                  },
                  "external_ref": {
                    "type": "string",
                    "description": "Your own reference for it, unique per account."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Which client it's for (your own brand if left out)."
                  },
                  "id": {
                    "type": "string",
                    "description": "Its ID (made from the name if left out)."
                  },
                  "mail_date": {
                    "type": "string",
                    "description": "YYYY-MM-DD, when it mails."
                  },
                  "ends_at": {
                    "type": "string",
                    "description": "When the codes stop (ISO date and time)."
                  },
                  "crm_webhook": {
                    "type": "string",
                    "description": "A CRM web address each response is sent to (plans with CRM webhooks)."
                  },
                  "copy_from": {
                    "type": "string",
                    "description": "Start from another campaign's settings (look, versions, fallback page)."
                  },
                  "variants": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "A/B versions: [{key, label, destination}], up to 6. key: 1–12 letters or numbers, like A. destination: where that version's codes go (the campaign's if left out)."
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "campaign": {
                    "id": "spring-tune-up",
                    "name": "Spring tune-up",
                    "external_ref": "N208057",
                    "destination": "https://example.com/spring",
                    "codes": 0,
                    "archived": false
                  },
                  "created": true
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/{id}": {
      "get": {
        "summary": "One campaign",
        "description": "One campaign.",
        "tags": [
          "Campaigns"
        ],
        "x-scope": "campaigns:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {}
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Change a campaign's name, destination, mail date, end date, CRM webhook, client, external_ref or A/B versions",
        "description": "Change a campaign's name, destination, mail date, end date, CRM webhook, client, external_ref or A/B versions. Printed codes follow at once.",
        "tags": [
          "Campaigns"
        ],
        "x-scope": "campaigns:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": ""
                  },
                  "destination": {
                    "type": "string",
                    "description": ""
                  },
                  "mail_date": {
                    "type": "string",
                    "description": ""
                  },
                  "ends_at": {
                    "type": "string",
                    "description": ""
                  },
                  "crm_webhook": {
                    "type": "string",
                    "description": "Empty removes it."
                  },
                  "client_id": {
                    "type": "string",
                    "description": ""
                  },
                  "external_ref": {
                    "type": "string",
                    "description": ""
                  },
                  "variants": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "The whole list of A/B versions ([{key, label, destination}]); send the ones you have plus any new ones. An empty list removes them."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {}
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/{id}/codes": {
      "post": {
        "summary": "One code per person, up to 5,000 rows a request (500 on Free)",
        "description": "One code per person, up to 5,000 rows a request (500 on Free). The whole batch is checked against the month's codes before anything is made: all of it is made, or none. A row whose external_id already has a code in this campaign gets that code back (created: false), so sending the same list again, or a list with a few names added, never makes duplicates. Send \"dry_run\": true first to see how many are new and whether they fit.",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "rows"
                ],
                "properties": {
                  "rows": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "[{external_id, ref, zip, variant, slug, fields}]. external_id: your ID for the person (customer number, email, row ID), unique per campaign. ref: what the portal shows for them (defaults to external_id). zip: for results by ZIP. variant: A/B version. slug: start the code with their name (JORDAN7K). fields: up to 12 columns kept with the code."
                  },
                  "dry_run": {
                    "type": "boolean",
                    "description": "Check only: how many are new, how many exist, whether they fit this month."
                  },
                  "slug_mode": {
                    "type": "string",
                    "description": "suffix (default, JORDAN7K) or plain (JORDAN when it's free)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "campaign_id": "spring-tune-up",
                  "created": 1,
                  "existing": 1,
                  "codes": [
                    {
                      "code": "JORDAN7K",
                      "url": "https://pipic.link/JORDAN7K",
                      "qr_data": "HTTPS://PIPIC.LINK/JORDAN7K",
                      "print_url": "pipic.link/JORDAN7K",
                      "external_id": "C1001",
                      "ref": "C1001",
                      "zip": "52240",
                      "created": true
                    },
                    {
                      "code": "K7M2QX",
                      "url": "https://pipic.link/K7M2QX",
                      "qr_data": "HTTPS://PIPIC.LINK/K7M2QX",
                      "print_url": "pipic.link/K7M2QX",
                      "external_id": "C1002",
                      "created": false
                    }
                  ]
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "A campaign's codes, 500 at a time (next_cursor for the next page), or the ones for some external_ids",
        "description": "A campaign's codes, 500 at a time (next_cursor for the next page), or the ones for some external_ids.",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Up to 1,000 (default 500).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "next_cursor from the page before.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Repeat for up to 100 people.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {}
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/codes": {
      "post": {
        "summary": "A one-off code (Links & QR codes): a web page, contact card, call, text, email or Wi-Fi",
        "description": "A one-off code (Links & QR codes): a web page, contact card, call, text, email or Wi-Fi. With an external_id, sending it again returns the same code.",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "destination"
                ],
                "properties": {
                  "destination": {
                    "type": "string",
                    "description": "The web address it opens (type url)."
                  },
                  "type": {
                    "type": "string",
                    "description": "url (default), vcard, call, sms, email or wifi."
                  },
                  "content": {
                    "type": "object",
                    "description": "What a vcard, call, sms, email or wifi code holds (same fields as the portal)."
                  },
                  "label": {
                    "type": "string",
                    "description": "A name for it."
                  },
                  "client_id": {
                    "type": "string",
                    "description": ""
                  },
                  "external_id": {
                    "type": "string",
                    "description": "Your own ID for it, unique among one-off codes."
                  },
                  "code": {
                    "type": "string",
                    "description": "A custom code (4–24 letters or numbers)."
                  },
                  "utm_source": {
                    "type": "string",
                    "description": ""
                  },
                  "utm_medium": {
                    "type": "string",
                    "description": ""
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "code": {
                    "code": "SPRING",
                    "url": "https://pipic.link/SPRING",
                    "qr_data": "HTTPS://PIPIC.LINK/SPRING",
                    "print_url": "pipic.link/SPRING",
                    "type": "url",
                    "destination": "https://example.com/spring"
                  },
                  "created": true
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/codes/{code}": {
      "get": {
        "summary": "One code: where it goes, its scans so far",
        "description": "One code: where it goes, its scans so far.",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:read",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {}
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Change where a code goes or turn it off",
        "description": "Change where a code goes or turn it off. One-off codes can also change their label, type and content.",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:write",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "destination": {
                    "type": "string",
                    "description": "Campaign codes: empty sends it back to the campaign's destination."
                  },
                  "active": {
                    "type": "boolean",
                    "description": ""
                  },
                  "label": {
                    "type": "string",
                    "description": ""
                  },
                  "external_id": {
                    "type": "string",
                    "description": ""
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {}
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/codes/{code}/qr.pdf": {
      "get": {
        "summary": "Print-ready artwork for one code: vector PDF in CMYK, in the code's saved look (its own, else its campaign's), with the logo when the look has one",
        "description": "Print-ready artwork for one code: vector PDF in CMYK, in the code's saved look (its own, else its campaign's), with the logo when the look has one.",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:read",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "description": "Finished width in inches, 0.5 to 12.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {}
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/codes/{code}/qr.svg": {
      "get": {
        "summary": "The same code as an SVG for screens (RGB, no logo)",
        "description": "The same code as an SVG for screens (RGB, no logo).",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:read",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "description": "Width in inches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/svg+xml": {}
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/{id}/artwork": {
      "post": {
        "summary": "Print-ready artwork for up to 200 of a campaign's codes in one request: one vector CMYK PDF per code (base64) in the campaign's saved look, or SVGs",
        "description": "Print-ready artwork for up to 200 of a campaign's codes in one request: one vector CMYK PDF per code (base64) in the campaign's saved look, or SVGs. For variable-data layouts that place a file per person (InDesign Data Merge image fields).",
        "tags": [
          "Codes"
        ],
        "x-scope": "codes:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "codes"
                ],
                "properties": {
                  "codes": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "Up to 200 of the campaign's codes."
                  },
                  "format": {
                    "type": "string",
                    "description": "pdf (default) or svg."
                  },
                  "size": {
                    "type": "number",
                    "description": "Finished width in inches, 0.5 to 12 (the look's size if left out)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "campaign_id": "spring-tune-up",
                  "format": "pdf",
                  "size": 1,
                  "files": [
                    {
                      "code": "JORDAN7K",
                      "name": "JORDAN7K.pdf",
                      "pdf": "JVBERi0xLjQK…"
                    }
                  ],
                  "missing": []
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/campaigns/{id}/stats": {
      "get": {
        "summary": "Codes, people who responded, scans, conversions and form responses, by day (90 days), by ZIP and by version",
        "description": "Codes, people who responded, scans, conversions and form responses, by day (90 days), by ZIP and by version. Bots and email scanners are already set aside.",
        "tags": [
          "Results"
        ],
        "x-scope": "stats:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "stats": {
                    "campaign_id": "spring-tune-up",
                    "codes": 2000,
                    "people": 96,
                    "response_rate": 4.8,
                    "scans": 131,
                    "set_aside": {
                      "suspect": 4,
                      "bots": 22
                    },
                    "conversions": 12,
                    "form_responses": 30,
                    "by_day": [
                      {
                        "day": "2026-11-05",
                        "scans": 40
                      }
                    ],
                    "by_zip": [
                      {
                        "zip": "52245",
                        "mailed": 400,
                        "responded": 45,
                        "rate": 11.25
                      }
                    ]
                  }
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/device": {
      "post": {
        "summary": "For apps (like the InDesign plugin): start a connection",
        "description": "For apps (like the InDesign plugin): start a connection. Show the user_code and open verification_url; the account owner approves it in the portal.",
        "tags": [
          "Connect a device"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "What the owner sees, like \"InDesign on Sara's Mac\"."
                  },
                  "client": {
                    "type": "string",
                    "description": "Your app, like indesign."
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "device_code": "pld_…",
                  "user_code": "KDPW-3QXT",
                  "verification_url": "https://admin.pipic.link/#/settings/api?connect=KDPW-3QXT",
                  "expires_in": 900,
                  "interval": 5
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/device/token": {
      "post": {
        "summary": "Check every interval seconds",
        "description": "Check every interval seconds. 202 while it waits; once approved, the app's own key (shown this once).",
        "tags": [
          "Connect a device"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "device_code"
                ],
                "properties": {
                  "device_code": {
                    "type": "string",
                    "description": "From POST /v1/device."
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "status": "approved",
                  "api_key": "pl_live_…",
                  "key": {
                    "id": "k…",
                    "name": "InDesign on Sara's Mac",
                    "scopes": [
                      "codes:write"
                    ]
                  },
                  "account": {
                    "id": "pip-iowa-city",
                    "name": "PIP Iowa City"
                  }
                }
              }
            }
          },
          "default": {
            "description": "An error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}