{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://teamshift.io/human-api/task-spec/v1/receipt.schema.json",
  "title": "Task receipt",
  "description": "A W3C Verifiable Credential 2.0 issued by did:web:teamshift.io for a verified task, signed with an eddsa-jcs-2022 Data Integrity proof. Holds the ZIP code only, never the street address or GPS.",
  "type": "object",
  "required": [
    "@context",
    "id",
    "type",
    "issuer",
    "validFrom",
    "credentialSubject"
  ],
  "properties": {
    "@context": {
      "const": [
        "https://www.w3.org/ns/credentials/v2"
      ]
    },
    "id": {
      "type": "string",
      "pattern": "^urn:uuid:"
    },
    "type": {
      "const": [
        "VerifiableCredential",
        "TaskReceipt"
      ]
    },
    "issuer": {
      "const": "did:web:teamshift.io"
    },
    "validFrom": {
      "type": "string",
      "format": "date-time"
    },
    "credentialSubject": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "taskId",
        "taskType",
        "zip",
        "worker",
        "completedAt",
        "outcome",
        "proofs",
        "price"
      ],
      "properties": {
        "taskId": {
          "type": "string"
        },
        "taskType": {
          "type": "string"
        },
        "zip": {
          "anyOf": [
            {
              "$ref": "common.schema.json#/$defs/zip"
            },
            {
              "type": "null"
            }
          ]
        },
        "worker": {
          "type": "string",
          "pattern": "^w_[0-9a-f]{16}$",
          "description": "Pseudonymous worker ID."
        },
        "dispatchedAt": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "completedAt": {
          "type": "string",
          "format": "date-time"
        },
        "outcome": {
          "const": "verified"
        },
        "proofSourceBound": {
          "type": "boolean",
          "description": "Every proof file came from the worker's own reply."
        },
        "proofConfidence": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "score",
                "band",
                "reasons"
              ],
              "properties": {
                "score": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 100
                },
                "band": {
                  "enum": [
                    "high",
                    "medium",
                    "low"
                  ]
                },
                "reasons": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          ]
        },
        "proofs": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "sha256"
            ],
            "properties": {
              "sha256": {
                "type": "string",
                "pattern": "^[0-9a-f]{64}$"
              },
              "receivedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "capturedAt": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Capture time the photo itself carries, when it kept one."
              },
              "withinRadius": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Whether the photo was taken inside the task's radius; null when it could not be checked."
              }
            }
          }
        },
        "price": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "currency",
            "lines",
            "totalCents"
          ],
          "properties": {
            "currency": {
              "const": "usd"
            },
            "lines": {
              "type": "array",
              "contains": {
                "type": "object",
                "properties": {
                  "kind": {
                    "const": "platform_fee"
                  }
                }
              },
              "minContains": 1,
              "maxContains": 1,
              "items": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "kind",
                  "amountCents"
                ],
                "properties": {
                  "kind": {
                    "enum": [
                      "worker_pay",
                      "platform_fee",
                      "pass_through",
                      "tax",
                      "credit"
                    ]
                  },
                  "amountCents": {
                    "type": "integer"
                  }
                }
              }
            },
            "totalCents": {
              "type": "integer"
            }
          }
        }
      }
    },
    "proof": {
      "type": "object",
      "required": [
        "type",
        "cryptosuite",
        "verificationMethod",
        "proofPurpose",
        "proofValue"
      ],
      "properties": {
        "type": {
          "const": "DataIntegrityProof"
        },
        "cryptosuite": {
          "const": "eddsa-jcs-2022"
        },
        "created": {
          "type": "string",
          "format": "date-time"
        },
        "verificationMethod": {
          "const": "did:web:teamshift.io#receipt-key-1"
        },
        "proofPurpose": {
          "const": "assertionMethod"
        },
        "proofValue": {
          "type": "string",
          "pattern": "^z[1-9A-HJ-NP-Za-km-z]+$"
        }
      }
    }
  }
}
