CarbonGuru Webhooks API

Endpoint registrations and the per-attempt delivery log.

Operations 6

GET /v1/webhook-endpoints The account's webhook endpoints #
POST /v1/webhook-endpoints Register a webhook endpoint #
DELETE /v1/webhook-endpoints/{endpoint_id} Stop delivering to this endpoint #
POST /v1/webhook-endpoints/{endpoint_id}/rotate-secret Mint a new signing secret for this endpoint #
GET /v1/webhook-deliveries The per-attempt delivery log #
POST /v1/webhook-deliveries/{delivery_id}/replay Send this delivery again #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/carbonguru-io:carbonguru-io-webhooks-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

carbonguru-io-webhooks-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: CarbonGuru Webhooks API
  version: 0.1.0
  summary: Carbon footprint analysis, history and reference data for a developer's own server.
  description: 'One API over the CarbonGuru platform: carbon-footprint analysis of products, carts, text, structured items and files; the sessions, exports and history those analyses produce; reference data; offsets for the account itself; and, for an account with a connected store, catalog footprints, the live footprint read, offset ordering and webhooks. Authenticate with `Authorization: Bearer `. A test key, made in the same place, connects the same way and records every order it posts as a preview: nothing is bought. Errors are RFC 9457 problem documents. Every response carries `X-Request-ID`. Writes accept an `Idempotency-Key`. Lists page with an opaque `next_cursor`. No route accepts terms, saves a payment method or starts automatic offsetting: a signed-in person does those in the account.'
  contact:
    name: CarbonGuru
    url: https://carbonguru.io
servers:
- url: https://carbonguru.io
  description: Production
security:
- bearerAuth: []
tags:
- name: Webhooks
  description: Endpoint registrations and the per-attempt delivery log.
paths:
  /v1/webhook-endpoints:
    get:
      tags:
      - Webhooks
      operationId: listWebhookEndpoints
      summary: The account's webhook endpoints
      description: 'No secret is in this answer. A secret appears in exactly two responses: creating an endpoint and rotating its secret.'
      security:
      - bearerAuth:
        - carbon:read
      responses:
        '200':
          description: The registered endpoints.
          headers:
            X-Request-ID:
              $ref: '#/components/headers/XRequestID'
          content:
            application/json:
              schema:
                type: object
                required:
                - endpoints
                properties:
                  endpoints:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebhookEndpoint'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      tags:
      - Webhooks
      operationId: createWebhookEndpoint
      summary: Register a webhook endpoint
      description: 'THE SECRET IS IN THIS ANSWER ONLY. Store it when you read it: we hold a verifier for it, not the value, and no route says it again. An endpoint whose secret was lost is rotated. The URL must be https on 443 and must not resolve inside our network; a URL that is not is a 422 invalid_url, and an event we do not fire is a 422 unknown_event. A key may subscribe only to events whose scope it holds. Idempotency-Key applies to the registration and not to the secret: a replay under the same key is a 409 idempotency_secret_not_replayable.'
      security:
      - bearerAuth:
        - carbon:read
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - url
              - events
              properties:
                url:
                  type: string
                  description: An https endpoint on port 443.
                events:
                  type: array
                  minItems: 1
                  items:
                    type: string
                  description: catalog.push.completed, footprint.updated, order.offset, charge.failed, settlement.completed, certificate.issued, analysis.completed, analysis.failed.
            example:
              url: https://shop.example/hooks/carbonguru
              events:
              - catalog.push.completed
              - footprint.updated
      responses:
        '201':
          description: Registered. The secret is stated once, here.
          headers:
            X-Request-ID:
              $ref: '#/components/headers/XRequestID'
          content:
            application/json:
              schema:
                type: object
                required:
                - endpoint
                - secret
                properties:
                  endpoint:
                    $ref: '#/components/schemas/WebhookEndpoint'
                  secret:
                    type: string
                    description: The signing secret, whsec_… Standard Webhooks signing. It is never returned again.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/UnprocessableContent'
  /v1/webhook-endpoints/{endpoint_id}:
    delete:
      tags:
      - Webhooks
      operationId: deleteWebhookEndpoint
      summary: Stop delivering to this endpoint
      description: The endpoint's delivery log stays readable afterwards.
      security:
      - bearerAuth:
        - carbon:read
      parameters:
      - $ref: '#/components/parameters/WebhookEndpointId'
      responses:
        '204':
          description: Deleted. No body.
          headers:
            X-Request-ID:
              $ref: '#/components/headers/XRequestID'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/webhook-endpoints/{endpoint_id}/rotate-secret:
    post:
      tags:
      - Webhooks
      operationId: rotateWebhookSecret
      summary: Mint a new signing secret for this endpoint
      description: THE SECRET IS IN THIS ANSWER ONLY. The endpoint keeps its id, its URL and its events; deliveries after this call are signed with the new secret.
      security:
      - bearerAuth:
        - carbon:read
      parameters:
      - $ref: '#/components/parameters/WebhookEndpointId'
      responses:
        '200':
          description: The new signing secret, stated once.
          headers:
            X-Request-ID:
              $ref: '#/components/headers/XRequestID'
          content:
            application/json:
              schema:
                type: object
                required:
                - secret
                properties:
                  secret:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/webhook-deliveries:
    get:
      tags:
      - Webhooks
      operationId: listWebhookDeliveries
      summary: The per-attempt delivery log
      description: One row per attempt with its status code, its error and when the next attempt is due. Cursor-paged; next_cursor is opaque and the Link header carries the same cursor as rel="next".
      security:
      - bearerAuth:
        - carbon:read
      parameters:
      - name: endpoint_id
        in: query
        required: false
        schema:
          type: string
      - name: status
        in: query
        required: false
        schema:
          type: string
        description: pending, delivered or failed.
      - name: cursor
        in: query
        required: false
        schema:
          type: string
        description: A next_cursor from an earlier page. Wins over limit.
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          default: 25
          minimum: 1
          maximum: 100
      responses:
        '200':
          description: A page of delivery attempts.
          headers:
            X-Request-ID:
              $ref: '#/components/headers/XRequestID'
            Link:
              description: RFC 8288. rel="next" when another page exists.
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
                required:
                - deliveries
                - next_cursor
                properties:
                  deliveries:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebhookDelivery'
                  next_cursor:
                    type:
                    - string
                    - 'null'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableContent'
  /v1/webhook-deliveries/{delivery_id}/replay:
    post:
      tags:
      - Webhooks
      operationId: replayWebhookDelivery
      summary: Send this delivery again
      description: The replay is a new attempt on the same log row.
      security:
      - bearerAuth:
        - carbon:read
      parameters:
      - name: delivery_id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '202':
          description: The replay was accepted.
          headers:
            X-Request-ID:
              $ref: '#/components/headers/XRequestID'
            Idempotent-Replayed:
              $ref: '#/components/headers/IdempotentReplayed'
          content:
            application/json:
              schema:
                type: object
                required:
                - delivery
                properties:
                  delivery:
                    $ref: '#/components/schemas/WebhookDelivery'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
components:
  schemas:
    Problem:
      type: object
      description: RFC 9457 problem document. Served as application/problem+json.
      required:
      - type
      - title
      - status
      - detail
      - code
      - request_id
      properties:
        type:
          type: string
          description: A stable identifier for this problem kind.
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        code:
          type: string
          description: The machine-readable name to branch on.
        request_id:
          type: string
        errors:
          type: array
          description: Field-level problems, when the refusal is about the request's fields.
          items:
            type: object
        required_scope:
          type: string
          description: Present on insufficient_scope.
        retry_after:
          type: string
          description: Present on a 429, beside the Retry-After header.
        max_size_bytes:
          type: integer
          description: Present on file_too_large.
        min_tier:
          type: string
          description: Present on feature_not_entitled.
        current_tier:
          type: string
          description: Present on feature_not_entitled.
        upgrade_url:
          type: string
          description: Present on feature_not_entitled.
        details:
          type: object
          description: Present on mapping_limit_exceeded.
    WebhookDelivery:
      type: object
      description: 'One delivery attempt. Read it when an endpoint stopped receiving: it says what we sent, what came back, and when the next attempt is due.'
      properties:
        id:
          type: string
        endpoint_id:
          type: string
        event_id:
          type: string
          description: The event this delivery carries. Retries of one event share it.
        event_type:
          type: string
        status:
          type: string
          description: pending, delivered or failed.
        attempt_count:
          type:
          - integer
          - 'null'
        last_status_code:
          type:
          - integer
          - 'null'
          description: The HTTP status the endpoint answered with.
        last_error:
          type:
          - string
          - 'null'
        created_at:
          type:
          - string
          - 'null'
        delivered_at:
          type:
          - string
          - 'null'
        next_attempt_at:
          type:
          - string
          - 'null'
          description: Null when no further attempt is due.
    WebhookEndpoint:
      type: object
      description: 'One registered webhook endpoint. The signing secret is not part of the resource: it is stated once at registration and once at each rotation, and nowhere else.'
      properties:
        id:
          type: string
        url:
          type: string
        events:
          type: array
          items:
            type: string
          description: The events this endpoint subscribes to.
        status:
          type: string
          description: active or disabled. An endpoint is disabled after repeated delivery failures.
        created_at:
          type:
          - string
          - 'null'
        failure_count:
          type:
          - integer
          - 'null'
          description: Consecutive failed deliveries. It resets on a success.
        disabled_at:
          type:
          - string
          - 'null'
  headers:
    XRequestID:
      description: The request id, echoed from the caller when it is a sane token, else minted. On every response and in every log line.
      schema:
        type: string
    IdempotentReplayed:
      description: Present and true when this response was stored by an earlier request under the same Idempotency-Key and replayed rather than processed again.
      schema:
        type: string
        enum:
        - 'true'
  responses:
    Forbidden:
      description: A missing scope, an exhausted analysis allowance, or an object that is not the caller's.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/XRequestID'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    NotFound:
      description: No such resource.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/XRequestID'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Conflict:
      description: An Idempotency-Key was reused with a different body (idempotency_key_reuse), or a request under the same key is still running (idempotency_in_progress).
      headers:
        X-Request-ID:
          $ref: '#/components/headers/XRequestID'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unauthorized:
      description: No valid credential. Every authentication failure returns this one document.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/XRequestID'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    UnprocessableContent:
      description: The request's fields are wrong. errors[] names them.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/XRequestID'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  parameters:
    WebhookEndpointId:
      name: endpoint_id
      in: path
      required: true
      schema:
        type: string
      description: The endpoint id the registration returned.
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        minLength: 1
        maxLength: 255
      description: 'A key of the caller''s choosing, held 24 hours and scoped to the account, the method and the path. The same key with the same body replays the stored response with Idempotent-Replayed: true. The same key with a different body is a 409 idempotency_key_reuse. A request still running under the key is a 409 idempotency_in_progress. A key longer than 255 characters or holding control characters is a 422. A write whose record cannot be stored is still processed once, without the replay guarantee. A response carrying a secret is never replayed: the second request receives a 409 idempotency_secret_not_replayable.'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An API key from /my-account/api/ (`sk_merchant_…`), or a CarbonGuru OAuth access token. A test key (`sk_merchant_test_…`) connects like a live key; every order it posts is recorded as a preview and nothing is bought. Auth runs before body validation, and every failure returns the same 401.