{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Soca API",
    "version": "1.0.0",
    "description": "Create non-custodial USDC invoices and subscriptions, read payment state, ingest usage, and manage credits and entitlements.",
    "contact": {
      "name": "Soca",
      "url": "https://soca.finance"
    }
  },
  "servers": [
    {
      "url": "https://soca.finance",
      "description": "Soca API"
    }
  ],
  "externalDocs": {
    "description": "Soca developer documentation",
    "url": "https://soca.finance/docs/developers/api-reference"
  },
  "tags": [
    {
      "name": "Invoices"
    },
    {
      "name": "Plans"
    },
    {
      "name": "Payments"
    },
    {
      "name": "Subscriptions"
    },
    {
      "name": "Events"
    },
    {
      "name": "Usage"
    },
    {
      "name": "Credits"
    },
    {
      "name": "Entitlements"
    }
  ],
  "paths": {
    "/v1/invoices": {
      "post": {
        "tags": [
          "Invoices"
        ],
        "operationId": "postV1Invoices",
        "summary": "Create a one-time invoice",
        "description": "Create a one-time invoice. Returns a hosted, non-custodial checkout_url to send the customer; no money moves until they pay, then an invoice.paid webhook fires.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    },
                    "amount": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "checkout_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "object",
                    "id",
                    "amount",
                    "status",
                    "checkout_url"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "invoice",
                  "id": "inv_...",
                  "amount": "2500000",
                  "status": "open",
                  "checkout_url": "https://soca.to/invoice/inv_..."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+$"
                      }
                    ],
                    "description": "USDC base units: 2500000 = 2.50 USDC. Must be a positive integer."
                  },
                  "description": {
                    "type": "string",
                    "description": "Shown on the hosted checkout page. 1–500 characters."
                  },
                  "memo": {
                    "type": "string",
                    "description": "Free-form note, up to 200 characters."
                  },
                  "invoice_number": {
                    "type": "string",
                    "description": "Your own reference, up to 100 characters."
                  },
                  "recipient": {
                    "type": "string",
                    "description": "Who it is billed to: a label or email for your records, up to 200 characters."
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO-8601 due date."
                  }
                },
                "required": [
                  "amount",
                  "description"
                ],
                "additionalProperties": false
              },
              "example": {
                "amount": "2500000",
                "description": "Acme Pro, March",
                "invoice_number": "INV-1041"
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Invoices"
        ],
        "operationId": "getV1Invoices",
        "summary": "List invoices, newest first",
        "description": "List invoices, newest first. Standard list envelope with cursor pagination.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 25.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "description": "1–100, default 25."
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "ISO timestamp cursor. Pass the previous page's next_cursor.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "ISO timestamp cursor. Pass the previous page's next_cursor."
            }
          }
        ]
      }
    },
    "/v1/plans": {
      "post": {
        "tags": [
          "Plans"
        ],
        "operationId": "postV1Plans",
        "summary": "Create a subscription plan (product + price + platform-signed on-chain plan)",
        "description": "Create a subscription plan (product + price + platform-signed on-chain plan). Returns a hosted checkout_url for subscribers; the first successful charge fires subscription.active. Minimum price is 1.00 USDC. Plans are create-only; there is no GET /v1/plans yet.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    },
                    "amount": {
                      "type": "string"
                    },
                    "interval": {
                      "type": "string"
                    },
                    "product": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "description": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description"
                      ],
                      "additionalProperties": true
                    },
                    "checkout_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "object",
                    "id",
                    "amount",
                    "interval",
                    "product",
                    "checkout_url"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "plan",
                  "id": "price_...",
                  "amount": "9000000",
                  "interval": "month",
                  "product": {
                    "id": "prod_...",
                    "name": "Pro",
                    "description": null
                  },
                  "checkout_url": "https://soca.to/pay/price_..."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The plan/product name, 2–80 characters."
                  },
                  "amount": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+$"
                      }
                    ],
                    "description": "USDC base units charged per period. Minimum 1000000 (1.00 USDC); below that returns 400 amount_too_small."
                  },
                  "interval": {
                    "type": "string",
                    "enum": [
                      "week",
                      "biweekly",
                      "month",
                      "year",
                      "custom"
                    ],
                    "description": "One of week, biweekly, month, year, custom."
                  },
                  "interval_days": {
                    "type": "integer",
                    "description": "Required when interval is custom: days per billing period, 1–365."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional, up to 300 characters."
                  },
                  "usage_type": {
                    "type": "string",
                    "description": "licensed (default) charges the fixed amount each period. metered bills the customer’s usage each period instead, and amount becomes the per-period cap (the most that can be pulled). Metered plans take no charge at subscribe."
                  },
                  "meter": {
                    "type": "string",
                    "description": "Required when usage_type is metered: the meter id (from POST /v1/meters or GET /v1/meters) whose per-period usage is billed."
                  },
                  "pricing_model": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Required when usage_type is metered: how usage is priced. One of {\"kind\":\"per_unit\",\"unitAmount\":100,\"includedUnits\":0}, {\"kind\":\"package\",\"unitAmount\":...,\"packageSize\":...}, {\"kind\":\"tiered\",\"mode\":\"graduated\"|\"volume\",\"tiers\":[{\"upTo\":1000,\"unitAmount\":...},{\"upTo\":null,\"unitAmount\":...}]}, or {\"kind\":\"flat\",\"amount\":...}. Amounts are USDC base units; the last tier’s upTo must be null."
                  }
                },
                "required": [
                  "name",
                  "amount",
                  "interval"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/payments": {
      "get": {
        "tags": [
          "Payments"
        ],
        "operationId": "getV1Payments",
        "summary": "List confirmed on-chain payments, newest first.",
        "description": "List confirmed on-chain payments, newest first.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 25.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "description": "1–100, default 25."
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "ISO timestamp cursor from next_cursor.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "ISO timestamp cursor from next_cursor."
            }
          }
        ]
      }
    },
    "/v1/subscriptions": {
      "get": {
        "tags": [
          "Subscriptions"
        ],
        "operationId": "getV1Subscriptions",
        "summary": "List subscriptions, newest first.",
        "description": "List subscriptions, newest first.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 25.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "description": "1–100, default 25."
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "ISO timestamp cursor from next_cursor.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "ISO timestamp cursor from next_cursor."
            }
          }
        ]
      }
    },
    "/v1/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "getV1Events",
        "summary": "List the event feed backing your webhooks, newest first",
        "description": "List the event feed backing your webhooks, newest first. Poll it or reconcile deliveries against it. Event types are listed in Webhooks and events.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 25.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "description": "1–100, default 25."
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "ISO timestamp cursor from next_cursor.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "ISO timestamp cursor from next_cursor."
            }
          }
        ]
      }
    },
    "/v1/meters": {
      "post": {
        "tags": [
          "Usage"
        ],
        "operationId": "postV1Meters",
        "summary": "Create a meter — the named thing usage is recorded against",
        "description": "Create a meter — the named thing usage is recorded against. Its key is the event_name you send events with. Idempotent by key (a repeat returns the existing meter). Create a meter before a metered plan or a metered feature can reference it.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    },
                    "key": {
                      "type": "string"
                    },
                    "display_name": {
                      "type": "string"
                    },
                    "aggregation": {
                      "type": "string"
                    },
                    "unit_label": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "object",
                    "id",
                    "key",
                    "display_name",
                    "aggregation",
                    "unit_label"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "meter",
                  "id": "meter_...",
                  "key": "api_calls",
                  "display_name": "API calls",
                  "aggregation": "sum",
                  "unit_label": "calls"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string",
                    "description": "The event name. Letters, numbers, dot, dash, underscore. Unique per account + mode."
                  },
                  "display_name": {
                    "type": "string",
                    "description": "Human name shown in the dashboard."
                  },
                  "aggregation": {
                    "type": "string",
                    "description": "How events roll into a period total: sum (default), count, max, or last."
                  },
                  "event_value_key": {
                    "type": "string",
                    "description": "The event property holding the quantity. Omit and each event counts as 1 (use with count)."
                  },
                  "unit_label": {
                    "type": "string",
                    "description": "Optional display unit, e.g. \"tokens\", \"requests\"."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional."
                  }
                },
                "required": [
                  "key",
                  "display_name"
                ],
                "additionalProperties": false
              },
              "example": {
                "key": "api_calls",
                "display_name": "API calls",
                "aggregation": "sum",
                "unit_label": "calls"
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Usage"
        ],
        "operationId": "getV1Meters",
        "summary": "List your usage meters, newest first",
        "description": "List your usage meters, newest first. Standard list envelope.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "object",
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "object": {
                      "type": "string",
                      "const": "list"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 25.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25,
              "description": "1–100, default 25."
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "ISO timestamp cursor from next_cursor.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "ISO timestamp cursor from next_cursor."
            }
          }
        ]
      }
    },
    "/v1/features": {
      "post": {
        "tags": [
          "API"
        ],
        "operationId": "postV1Features",
        "summary": "Create a feature — a capability you gate with entitlements",
        "description": "Create a feature — a capability you gate with entitlements. boolean (has it or not) or metered (has it, up to an allowance enforced against a meter). Idempotent by key. Create a feature before granting or checking it.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    },
                    "key": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "meter_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "object",
                    "id",
                    "key",
                    "name",
                    "type",
                    "meter_id"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "feature",
                  "id": "feat_...",
                  "key": "pro_models",
                  "name": "Pro models",
                  "type": "boolean",
                  "meter_id": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string",
                    "description": "The key you check access by. Letters, numbers, dot, dash, underscore."
                  },
                  "name": {
                    "type": "string",
                    "description": "Human name."
                  },
                  "type": {
                    "type": "string",
                    "description": "boolean (default) or metered."
                  },
                  "meter": {
                    "type": "string",
                    "description": "Required for a metered feature: the meter id whose usage counts against the allowance."
                  },
                  "unit_label": {
                    "type": "string",
                    "description": "Optional."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional."
                  }
                },
                "required": [
                  "key",
                  "name"
                ],
                "additionalProperties": false
              },
              "example": {
                "key": "pro_models",
                "name": "Pro models",
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "/v1/meter-events": {
      "post": {
        "tags": [
          "Usage"
        ],
        "operationId": "postV1MeterEvents",
        "summary": "Ingest usage: one event, or a batch of up to 500 as { \"events\": [...] }",
        "description": "Ingest usage: one event, or a batch of up to 500 as { \"events\": [...] }. Idempotent per idempotency_key (a body field per event, or an Idempotency-Key header for single events): retrying with the same key returns 200 with deduplicated: true instead of double-counting. The meter must exist first, or you get 404 unknown_meter. Rate limit: 600 requests/min.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event_name": {
                    "type": "string",
                    "description": "The meter's event name, as defined in the dashboard."
                  },
                  "value": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+$"
                      }
                    ],
                    "description": "Non-negative usage amount. Required for most meters; count-aggregated meters default each event to 1, while other aggregations return 400 missing_value without it."
                  },
                  "customer_id": {
                    "type": "string",
                    "description": "The Soca customer the usage belongs to."
                  },
                  "external_customer_id": {
                    "type": "string",
                    "description": "Your own stable customer identifier, which Soca upserts into a customer automatically."
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO-8601 event time. Defaults to now."
                  },
                  "idempotency_key": {
                    "type": "string",
                    "description": "Dedupe key, up to 255 characters. Safe to retry with the same key."
                  },
                  "properties": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Arbitrary JSON metadata stored with the event."
                  }
                },
                "required": [
                  "event_name"
                ],
                "additionalProperties": false
              },
              "example": {
                "event_name": "api_call",
                "external_customer_id": "user_812",
                "value": 3,
                "idempotency_key": "req_7f3a1c"
              }
            }
          }
        }
      }
    },
    "/v1/credit_grants": {
      "post": {
        "tags": [
          "Credits"
        ],
        "operationId": "postV1CreditGrants",
        "summary": "Top up a customer's prepaid credit balance",
        "description": "Top up a customer's prepaid credit balance. One of customer_id / external_customer_id is required (400 customer_required otherwise). Emits a credit.granted event.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "customer_id": {
                      "type": "string"
                    },
                    "granted": {
                      "type": "string"
                    },
                    "balance": {
                      "type": "string"
                    },
                    "entry_id": {
                      "type": "string"
                    },
                    "deduplicated": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "object",
                    "customer_id",
                    "granted",
                    "balance",
                    "entry_id",
                    "deduplicated"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "credit_grant",
                  "customer_id": "cus_...",
                  "granted": "50000000",
                  "balance": "50000000",
                  "entry_id": "...",
                  "deduplicated": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+$"
                      }
                    ],
                    "description": "USDC base units to add to the balance. Must be positive."
                  },
                  "customer_id": {
                    "type": "string",
                    "description": "The Soca customer to credit."
                  },
                  "external_customer_id": {
                    "type": "string",
                    "description": "Your own stable customer identifier, upserted automatically."
                  },
                  "reason": {
                    "type": "string",
                    "description": "Ledger note, up to 300 characters. Defaults to \"API grant\"."
                  },
                  "expires_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO-8601 expiry for the granted credits."
                  },
                  "idempotency_key": {
                    "type": "string",
                    "description": "Dedupe key, up to 255 characters."
                  }
                },
                "required": [
                  "amount"
                ],
                "additionalProperties": false
              },
              "example": {
                "external_customer_id": "user_812",
                "amount": "50000000",
                "reason": "Starter pack"
              }
            }
          }
        }
      }
    },
    "/v1/credit_debits": {
      "post": {
        "tags": [
          "Credits"
        ],
        "operationId": "postV1CreditDebits",
        "summary": "Draw down a customer's prepaid credits for usage",
        "description": "Draw down a customer's prepaid credits for usage. By default the debit covers only what the balance allows and returns the remainder as shortfall for you to bill separately; pass allow_negative: true to let the balance go below zero instead. The customer must already have a credit account (404 no_credit_account otherwise). Emits a credit.debited event. Rate limit: 120 requests/min.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "customer_id": {
                      "type": "string"
                    },
                    "requested": {
                      "type": "string"
                    },
                    "covered": {
                      "type": "string"
                    },
                    "shortfall": {
                      "type": "string"
                    },
                    "balance": {
                      "type": "string"
                    },
                    "deduplicated": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "object",
                    "customer_id",
                    "requested",
                    "covered",
                    "shortfall",
                    "balance",
                    "deduplicated"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "credit_debit",
                  "customer_id": "cus_...",
                  "requested": "1250000",
                  "covered": "1250000",
                  "shortfall": "0",
                  "balance": "48750000",
                  "deduplicated": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+$"
                      }
                    ],
                    "description": "USDC base units to draw down. Must be positive."
                  },
                  "customer_id": {
                    "type": "string",
                    "description": "The Soca customer to debit."
                  },
                  "external_customer_id": {
                    "type": "string",
                    "description": "Your own stable customer identifier."
                  },
                  "reason": {
                    "type": "string",
                    "description": "Ledger note, up to 300 characters. Defaults to \"API debit\"."
                  },
                  "allow_negative": {
                    "type": "boolean",
                    "description": "Allow the balance to go negative instead of reporting a shortfall. Default false."
                  },
                  "idempotency_key": {
                    "type": "string",
                    "description": "Dedupe key, up to 255 characters."
                  }
                },
                "required": [
                  "amount"
                ],
                "additionalProperties": false
              },
              "example": {
                "external_customer_id": "user_812",
                "amount": "1250000",
                "reason": "July overage"
              }
            }
          }
        }
      }
    },
    "/v1/customers/{id}/credit_balance": {
      "get": {
        "tags": [
          "Credits"
        ],
        "operationId": "getV1CustomersIdCreditBalance",
        "summary": "The customer's current prepaid balance plus ledger totals",
        "description": "The customer's current prepaid balance plus ledger totals. A customer with no credit account returns a plain zero balance. Rate limit: 240 requests/min.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The Soca customer id (path parameter). Unknown ids return 404 unknown_customer.",
            "schema": {
              "type": "string",
              "description": "The Soca customer id (path parameter). Unknown ids return 404 unknown_customer."
            }
          }
        ]
      }
    },
    "/v1/entitlement_grants": {
      "post": {
        "tags": [
          "Entitlements"
        ],
        "operationId": "postV1EntitlementGrants",
        "summary": "Grant a feature to a customer, optionally with a usage limit and an expiry",
        "description": "Grant a feature to a customer, optionally with a usage limit and an expiry. The feature must exist (404 unknown_feature), and one of customer_id / external_customer_id is required. Emits an entitlement.granted event.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    },
                    "feature": {
                      "type": "string"
                    },
                    "customer_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "object",
                    "id",
                    "feature",
                    "customer_id"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "entitlement_grant",
                  "id": "...",
                  "feature": "api_access",
                  "customer_id": "cus_..."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "feature_key": {
                    "type": "string",
                    "description": "The feature to grant, as defined in the dashboard."
                  },
                  "customer_id": {
                    "type": "string",
                    "description": "The Soca customer to grant to."
                  },
                  "external_customer_id": {
                    "type": "string",
                    "description": "Your own stable customer identifier, upserted automatically."
                  },
                  "limit_value": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string",
                        "pattern": "^[0-9]+$"
                      }
                    ],
                    "description": "For metered features: the usage limit (non-negative integer)."
                  },
                  "active_until": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO-8601 timestamp for when the entitlement lapses."
                  }
                },
                "required": [
                  "feature_key"
                ],
                "additionalProperties": false
              },
              "example": {
                "external_customer_id": "user_812",
                "feature_key": "api_access",
                "limit_value": "10000"
              }
            }
          }
        }
      }
    },
    "/v1/customers/{id}/entitlements/{feature_key}": {
      "get": {
        "tags": [
          "Entitlements"
        ],
        "operationId": "getV1CustomersIdEntitlementsFeatureKey",
        "summary": "The access-control check your backend calls before serving a feature answers two questions: is this customer entitled right now, and for metered features, how much of the limit remains",
        "description": "The access-control check your backend calls before serving a feature answers two questions: is this customer entitled right now, and for metered features, how much of the limit remains? reason is one of active, grace, no_grant, not_started, revoked, expired, limit_exceeded. Built for the hot path: 600 requests/min.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "customer_id": {
                      "type": "string"
                    },
                    "feature": {
                      "type": "string"
                    },
                    "entitled": {
                      "type": "boolean"
                    },
                    "reason": {
                      "type": "string"
                    },
                    "limit": {
                      "type": "string"
                    },
                    "used": {
                      "type": "string"
                    },
                    "remaining": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "object",
                    "customer_id",
                    "feature",
                    "entitled",
                    "reason",
                    "limit",
                    "used",
                    "remaining"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "object": "entitlement",
                  "customer_id": "cus_...",
                  "feature": "api_access",
                  "entitled": true,
                  "reason": "active",
                  "limit": "10000",
                  "used": "3120",
                  "remaining": "6880"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The Soca customer id (path parameter). Unknown ids return 404 unknown_customer.",
            "schema": {
              "type": "string",
              "description": "The Soca customer id (path parameter). Unknown ids return 404 unknown_customer."
            }
          },
          {
            "name": "feature_key",
            "in": "path",
            "required": true,
            "description": "The feature to check (path parameter). Unknown keys return 404 unknown_feature.",
            "schema": {
              "type": "string",
              "description": "The feature to check (path parameter). Unknown keys return 404 unknown_feature."
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Soca secret key",
        "description": "Use a server-side sk_test_... or sk_live_... secret key."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request was invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The API key is missing, invalid, or revoked.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "The request exceeded the applicable rate limit.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "x-soca-generated-from": "/docs/developers/api-reference"
}