> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fortiseval.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Request a credential evaluation

> Order a diploma, course-by-course, or work experience evaluation through the API and track it with webhooks

export const EvaluationLifecycleDiagram = () => <svg style={{
  width: "100%",
  height: "auto",
  display: "block"
}} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 590" role="img" aria-labelledby="evl-t evl-d">
    <title id="evl-t">Credential evaluation via the Fortis API</title>
    <desc id="evl-d">Your server uploads documents and creates a quote; Fortis sends quote.ready; you approve; Fortis sends order.created, order.in_progress and order.completed; you download the report.</desc>
    <defs>
      <filter id="evl-glow" x="-100%" y="-100%" width="300%" height="300%">
        <feGaussianBlur stdDeviation="3.5" result="b" />
        <feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge>
      </filter>
      <pattern id="evl-dots" width="20" height="20" patternUnits="userSpaceOnUse">
        <circle cx="1" cy="1" r="1" fill="#FFFFFF" opacity="0.045" />
      </pattern>
    </defs>
    <rect width="800" height="590" rx="14" fill="#1C1917" />
    <rect width="800" height="590" rx="14" fill="url(#evl-dots)" />
    
    <text x="32" y="38" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="12" fontWeight="600" letterSpacing="1.4" fill="#A8A29E">CREDENTIAL EVALUATION · REQUEST LIFECYCLE</text>
    <g fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="14" fontWeight="600" fill="#F5F5F4" textAnchor="middle">
    <rect x="90" y="58" width="160" height="38" rx="9" fill="#292524" stroke="#44403C" />
    <text x="170" y="82">Your server</text>
    <rect x="550" y="58" width="160" height="38" rx="9" fill="#292524" stroke="#44403C" />
    <text x="630" y="82">Fortis API</text>
    </g>
    <line x1="170" y1="96" x2="170" y2="540" stroke="#44403C" strokeWidth="1.5" strokeDasharray="3 5" />
    <line x1="630" y1="96" x2="630" y2="540" stroke="#44403C" strokeWidth="1.5" strokeDasharray="3 5" />
    <g><animate attributeName="opacity" values="1;1;0;0" keyTimes="0;0.9368;0.9684;1" dur="19s" repeatCount="indefinite" />
    <g>
    <line x1="176" y1="138" x2="624" y2="138" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.0368;0.0711;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 615 133 L 624 138 L 615 143" fill="none" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.0684;0.0737;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="128" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#FBBF24" opacity="0">POST /v1/files<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.0447;0.0605;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="156" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">Stage the diploma and transcript<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.0553;0.0711;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#FBBF24" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 176 138 L 624 138" keyPoints="0;0;1;1" keyTimes="0;0.0368;0.0711;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.0368;0.0432;0.0711;0.0774;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="624" cy="138" r="4" fill="none" stroke="#FBBF24" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.0711;0.1026;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.0711;0.0721;0.1026;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.0763;0.0921;1" dur="19s" repeatCount="indefinite" /><rect x="644" y="128" width="40" height="20" rx="10" fill="#FBBF24" fillOpacity="0.14" /><text x="664" y="142" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#FBBF24">201</text></g>
    </g>
    <g>
    <line x1="176" y1="192" x2="624" y2="192" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.1342;0.1684;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 615 187 L 624 192 L 615 197" fill="none" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.1658;0.1711;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="182" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#FBBF24" opacity="0">POST /v1/quotes<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.1421;0.1579;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="210" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">quote_type: academic_evaluation<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.1526;0.1684;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#FBBF24" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 176 192 L 624 192" keyPoints="0;0;1;1" keyTimes="0;0.1342;0.1684;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.1342;0.1405;0.1684;0.1747;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="624" cy="192" r="4" fill="none" stroke="#FBBF24" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.1684;0.2000;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.1684;0.1695;0.2000;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.1737;0.1895;1" dur="19s" repeatCount="indefinite" /><rect x="644" y="182" width="40" height="20" rx="10" fill="#FBBF24" fillOpacity="0.14" /><text x="664" y="196" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#FBBF24">201</text></g>
    </g>
    <g>
    <line x1="624" y1="246" x2="176" y2="246" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.2316;0.2658;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 185 241 L 176 246 L 185 251" fill="none" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.2632;0.2684;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="236" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#34D399" opacity="0">quote.ready<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.2395;0.2553;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="264" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">Priced · status: awaiting_payment<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.2500;0.2658;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#34D399" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 624 246 L 176 246" keyPoints="0;0;1;1" keyTimes="0;0.2316;0.2658;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.2316;0.2379;0.2658;0.2721;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="176" cy="246" r="4" fill="none" stroke="#34D399" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.2658;0.2974;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.2658;0.2668;0.2974;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.2711;0.2868;1" dur="19s" repeatCount="indefinite" /><rect x="116" y="236" width="40" height="20" rx="10" fill="#34D399" fillOpacity="0.14" /><text x="136" y="250" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#34D399">2xx</text></g>
    </g>
    <g>
    <line x1="176" y1="300" x2="624" y2="300" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.3289;0.3632;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 615 295 L 624 300 L 615 305" fill="none" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.3605;0.3658;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="290" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#FBBF24" opacity="0">POST /v1/quotes/{"{"}id{"}"}/approve<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.3368;0.3526;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="318" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">Creates the order, billed to your invoice<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.3474;0.3632;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#FBBF24" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 176 300 L 624 300" keyPoints="0;0;1;1" keyTimes="0;0.3289;0.3632;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.3289;0.3353;0.3632;0.3695;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="624" cy="300" r="4" fill="none" stroke="#FBBF24" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.3632;0.3947;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.3632;0.3642;0.3947;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.3684;0.3842;1" dur="19s" repeatCount="indefinite" /><rect x="644" y="290" width="40" height="20" rx="10" fill="#FBBF24" fillOpacity="0.14" /><text x="664" y="304" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#FBBF24">201</text></g>
    </g>
    <g>
    <line x1="624" y1="354" x2="176" y2="354" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.4263;0.4605;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 185 349 L 176 354 L 185 359" fill="none" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.4579;0.4632;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="344" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#34D399" opacity="0">order.created<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.4342;0.4500;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="372" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">ord_… · status: created<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.4447;0.4605;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#34D399" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 624 354 L 176 354" keyPoints="0;0;1;1" keyTimes="0;0.4263;0.4605;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.4263;0.4326;0.4605;0.4668;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="176" cy="354" r="4" fill="none" stroke="#34D399" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.4605;0.4921;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.4605;0.4616;0.4921;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.4658;0.4816;1" dur="19s" repeatCount="indefinite" /><rect x="116" y="344" width="40" height="20" rx="10" fill="#34D399" fillOpacity="0.14" /><text x="136" y="358" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#34D399">2xx</text></g>
    </g>
    <g>
    <line x1="624" y1="408" x2="176" y2="408" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.5237;0.5579;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 185 403 L 176 408 L 185 413" fill="none" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.5553;0.5605;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="398" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#34D399" opacity="0">order.in_progress<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.5316;0.5474;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="426" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">An evaluator is working on it<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.5421;0.5579;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#34D399" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 624 408 L 176 408" keyPoints="0;0;1;1" keyTimes="0;0.5237;0.5579;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.5237;0.5300;0.5579;0.5642;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="176" cy="408" r="4" fill="none" stroke="#34D399" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.5579;0.5895;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.5579;0.5589;0.5895;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.5632;0.5789;1" dur="19s" repeatCount="indefinite" /><rect x="116" y="398" width="40" height="20" rx="10" fill="#34D399" fillOpacity="0.14" /><text x="136" y="412" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#34D399">2xx</text></g>
    </g>
    <g>
    <line x1="624" y1="462" x2="176" y2="462" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.6211;0.6553;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 185 457 L 176 462 L 185 467" fill="none" stroke="#34D399" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.6526;0.6579;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="452" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#34D399" opacity="0">order.completed<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.6289;0.6447;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="480" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">The evaluation report is ready<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.6395;0.6553;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#34D399" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 624 462 L 176 462" keyPoints="0;0;1;1" keyTimes="0;0.6211;0.6553;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.6211;0.6274;0.6553;0.6616;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="176" cy="462" r="4" fill="none" stroke="#34D399" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.6553;0.6868;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.6553;0.6563;0.6868;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.6605;0.6763;1" dur="19s" repeatCount="indefinite" /><rect x="116" y="452" width="40" height="20" rx="10" fill="#34D399" fillOpacity="0.14" /><text x="136" y="466" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#34D399">2xx</text></g>
    </g>
    <g>
    <line x1="176" y1="516" x2="624" y2="516" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeDasharray="448" strokeDashoffset="448"><animate attributeName="stroke-dashoffset" values="448;448;0;0" keyTimes="0;0.7184;0.7526;1" dur="19s" repeatCount="indefinite" /></line>
    <path d="M 615 511 L 624 516 L 615 521" fill="none" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.7500;0.7553;1" dur="19s" repeatCount="indefinite" /></path>
    <text x="400.0" y="506" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="13" fill="#FBBF24" opacity="0">GET /v1/documents/{"{"}id{"}"}/download<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.7263;0.7421;1" dur="19s" repeatCount="indefinite" /></text>
    <text x="400.0" y="534" textAnchor="middle" fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="11.5" fill="#A8A29E" opacity="0">Signed URL, valid for 1 hour<animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.7368;0.7526;1" dur="19s" repeatCount="indefinite" /></text>
    <circle r="5" fill="#FBBF24" filter="url(#evl-glow)" opacity="0"><animateMotion path="M 176 516 L 624 516" keyPoints="0;0;1;1" keyTimes="0;0.7184;0.7526;1" calcMode="linear" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.7184;0.7247;0.7526;0.7589;1" dur="19s" repeatCount="indefinite" /></circle>
    <circle cx="624" cy="516" r="4" fill="none" stroke="#FBBF24" strokeWidth="2" opacity="0"><animate attributeName="r" values="4;4;18;18" keyTimes="0;0.7526;0.7842;1" dur="19s" repeatCount="indefinite" /><animate attributeName="opacity" values="0;0;0.9;0;0" keyTimes="0;0.7526;0.7537;0.7842;1" dur="19s" repeatCount="indefinite" /></circle>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.7579;0.7737;1" dur="19s" repeatCount="indefinite" /><rect x="644" y="506" width="40" height="20" rx="10" fill="#FBBF24" fillOpacity="0.14" /><text x="664" y="520" textAnchor="middle" fontFamily="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" fontSize="11" fill="#FBBF24">200</text></g>
    </g>
    </g>
    <g fontFamily="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" fontSize="12" fill="#A8A29E">
      <line x1="210" y1="566" x2="236" y2="566" stroke="#FBBF24" strokeWidth="2" strokeLinecap="round" />
      <text x="244" y="570">API request (you → Fortis)</text>
      <line x1="430" y1="566" x2="456" y2="566" stroke="#34D399" strokeWidth="2" strokeLinecap="round" />
      <text x="464" y="570">Webhook event (Fortis → you)</text>
    </g>
    
    </svg>;

This guide covers the full flow: you upload a candidate's academic documents,
request a quote, approve it, and download the finished evaluation report.
Webhooks tell you when each step happens, so you don't need to poll.

<Frame>
  <EvaluationLifecycleDiagram />
</Frame>

## Before you begin

You need:

* An **Internal app** API key (`sk-...`). See [Authentication](/authentication).
  The flow uses the `files:write`, `quotes:write`, `quotes:approve`,
  `orders:read`, `documents:read`, and `webhooks:manage` scopes.
* **Net-terms invoicing** on your account if you want to approve quotes through
  the API. Contact [support](mailto:support@fortiseval.com) to turn it on.
  Without it, you can still create quotes through the API and approve them in
  the [Customer Portal](https://portal.fortiseval.com).
* An HTTPS endpoint that can receive webhooks.

## Choose an evaluation type

Set `evaluation_type` on the quote to one of these values:

| `evaluation_type`             | What you get                                                                                                 |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `diploma_evaluation`          | The U.S. equivalency of each degree or diploma                                                               |
| `course_by_course_evaluation` | Every course listed with U.S. semester credits and grades, plus a GPA                                        |
| `work_experience_evaluation`  | An equivalency based on professional experience, for candidates whose work history substitutes for education |

Most employment and H-1B cases need a `diploma_evaluation`. Licensing boards,
universities, and credit transfers usually need a `course_by_course_evaluation`.
If you're not sure, add a question in `notes` and our team will confirm before
pricing the quote.

<Steps>
  <Step title="Register a webhook endpoint">
    Register your endpoint once and reuse it for every order. Subscribe to the
    quote, order, and file events:

    ```bash theme={null}
    curl https://api.fortiseval.com/v1/webhook-endpoints \
      -H "Authorization: Bearer sk-your-secret-key" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://example.com/webhooks/fortis",
        "events": ["quote.*", "order.*", "file.*"]
      }'
    ```

    The response contains the endpoint's signing secret (`whsec_...`). Store it
    somewhere safe. You need it to [verify signatures](/guides/webhooks#verifying-signatures).
  </Step>

  <Step title="Upload the candidate's documents">
    Upload each diploma, transcript, or mark sheet with the [files API](/guides/files):

    ```bash theme={null}
    curl https://api.fortiseval.com/v1/files \
      -H "Authorization: Bearer sk-your-secret-key" \
      -F "file=@/path/to/bachelor-diploma.pdf"
    ```

    ```json theme={null}
    {
      "message": "File uploaded successfully.",
      "data": {
        "id": "upload_3kR9vQ...",
        "status": "ready",
        "source": "direct_upload",
        "file_name": "bachelor-diploma.pdf",
        "mime_type": "application/pdf",
        "size": 482113
      }
    }
    ```

    Keep each `id`. If your documents are already hosted somewhere, skip this step
    and pass their URLs in `document_urls` when you create the quote.

    <Tip>
      Send the diploma **and** the transcript or mark sheets for every degree. A
      missing transcript is the most common reason a quote is delayed.
    </Tip>
  </Step>

  <Step title="Create the quote">
    ```bash theme={null}
    curl https://api.fortiseval.com/v1/quotes \
      -H "Authorization: Bearer sk-your-secret-key" \
      -H "Content-Type: application/json" \
      -d '{
        "quote_type": "academic_evaluation",
        "evaluation_type": "course_by_course_evaluation",
        "turnaround": "standard",
        "document_ids": ["upload_3kR9vQ...", "upload_8pLm2X..."],
        "candidate": {
          "first_name": "Priya",
          "last_name": "Raman",
          "visa_type": "h1b"
        },
        "reference": "CASE-1042",
        "cc_emails": ["paralegal@example.com"]
      }'
    ```

    The API responds with `201` and the new quote in status `requested`:

    ```json theme={null}
    {
      "message": "Quote request created successfully.",
      "data": {
        "id": "quot_Wd81nZ...",
        "status": "requested",
        "quote_type": "academic_evaluation",
        "requested_turnaround": "standard",
        "total_cents": 0,
        "items": [],
        "documents": [
          { "id": "doc_Yt4sPa...", "file_name": "bachelor-diploma.pdf", "document_role": "source" },
          { "id": "doc_Jq2mRb...", "file_name": "transcript.pdf", "document_role": "source" }
        ],
        "requested_at": "2026-09-24T14:02:11+00:00"
      }
    }
    ```

    Evaluation fields:

    | Field                                              | Required          | Description                                                                                                            |
    | -------------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------- |
    | `quote_type`                                       | Yes               | `academic_evaluation`                                                                                                  |
    | `evaluation_type`                                  | Yes               | See [Choose an evaluation type](#choose-an-evaluation-type)                                                            |
    | `document_ids` / `document_urls`                   | Yes, at least one | Up to 50 documents in total                                                                                            |
    | `turnaround`                                       | No                | `standard`, `expedited`, `next_day`, or `same_day` (rush)                                                              |
    | `desired_equivalency`                              | No                | The equivalency you need, such as `U.S. Bachelor of Science in Computer Science`                                       |
    | `translation_preference`                           | No                | `client_provided` if you include translations, or `translation_service` for us to translate foreign-language documents |
    | `candidate.first_name`, `middle_name`, `last_name` | No                | The person being evaluated, as their name should appear on the report                                                  |
    | `candidate.pronoun_type`                           | No                | `masculine`, `feminine`, or `neutral`. Controls pronouns in the report                                                 |
    | `candidate.visa_type`                              | No                | The visa or petition the evaluation supports, such as `h1b`, `o1a`, `eb2_niw`, `eb3`, or `other`                       |
    | `reference`                                        | No                | Your own case or matter ID                                                                                             |
    | `notes`                                            | No                | Instructions for our team, up to 10,000 characters                                                                     |
    | `cc_emails`                                        | No                | Up to 10 addresses to copy on updates                                                                                  |
    | `team`                                             | No                | A team token on your account                                                                                           |

    The [API reference](/api-reference) has the full list of `visa_type` values.
  </Step>

  <Step title="Wait for quote.ready">
    Our team reviews the documents and prices the quote. When it's ready, the quote
    moves to `awaiting_payment` and your endpoint receives `quote.ready`:

    ```json theme={null}
    {
      "id": "evt_01K5ZQ4T...",
      "type": "quote.ready",
      "api_version": "v1",
      "created": "2026-09-24T15:40:02+00:00",
      "data": {
        "object": {
          "id": "quot_Wd81nZ...",
          "status": "awaiting_payment",
          "quote_type": "academic_evaluation",
          "turnaround_label": "Standard",
          "total_cents": 18500,
          "total": "185.00",
          "items": [
            {
              "service_name": "Course-by-Course Evaluation",
              "quantity": 1,
              "price": 18500,
              "subtotal": 18500,
              "currency": "usd"
            }
          ],
          "expires_at": "2026-10-24T15:40:02+00:00"
        }
      }
    }
    ```

    Check `total_cents` and `items` before you approve. If the quote is cancelled,
    you receive `quote.cancelled`.
  </Step>

  <Step title="Approve the quote">
    ```bash theme={null}
    curl -X POST https://api.fortiseval.com/v1/quotes/quot_Wd81nZ.../approve \
      -H "Authorization: Bearer sk-your-secret-key"
    ```

    Approval creates the order and adds it to your open invoice. The response
    (`201`) is the new order:

    ```json theme={null}
    {
      "message": "Quote approved successfully.",
      "data": {
        "id": "ord_Ka93Lx...",
        "status": "created",
        "quote_id": "quot_Wd81nZ...",
        "total": 18500,
        "currency": "usd"
      }
    }
    ```

    You also receive `quote.approved` and `order.created`. If approval fails, the
    API returns `422` with an `error_code`. See
    [Approving quotes](/guides/quotes#approving-quotes) for the full list.
  </Step>

  <Step title="Track the order">
    The order sends an event each time its status changes:

    | Event                    | Order `status`    | What it means                          |
    | ------------------------ | ----------------- | -------------------------------------- |
    | `order.created`          | `created`         | The order is queued                    |
    | `order.in_progress`      | `in_progress`     | An evaluator is working on it          |
    | `order.ready_for_review` | `awaiting_review` | Deliverables are ready for your review |
    | `order.completed`        | `completed`       | The final report is ready to download  |
    | `order.cancelled`        | `cancelled`       | The order was cancelled                |
    | `order.refunded`         | `refunded`        | The order was refunded                 |

    Use `PUT /v1/orders/{id}` to attach your own `custom_reference` or
    `custom_metadata` to the order at any point.
  </Step>

  <Step title="Download the report">
    Order events don't include documents, so fetch the order when you receive
    `order.completed`:

    ```bash theme={null}
    curl https://api.fortiseval.com/v1/orders/ord_Ka93Lx... \
      -H "Authorization: Bearer sk-your-secret-key"
    ```

    The order's `documents` include the files you uploaded (`document_role: "source"`)
    and the deliverables. Evaluation reports have `document_role` set to
    `evaluation` or `course_evaluation`. Request a download URL for each one:

    ```bash theme={null}
    curl https://api.fortiseval.com/v1/documents/doc_Rm7cVd.../download \
      -H "Authorization: Bearer sk-your-secret-key"
    ```

    ```json theme={null}
    {
      "url": "https://...signed-download-url...",
      "file_name": "CBC-Raman-Course-by-Course-Evaluation.pdf",
      "mime_type": "application/pdf",
      "expires_at": "2026-09-30T18:12:44+00:00"
    }
    ```

    The URL expires after one hour. Download the file right away and store your own
    copy.
  </Step>
</Steps>

## Put it together

This Express handler verifies each event, then approves quotes under a budget
and downloads reports when orders complete. It uses the `verifyFortisSignature`
function from the [webhooks guide](/guides/webhooks#verifying-signatures).

```javascript Node.js theme={null}
import express from "express";

const app = express();
const API = "https://api.fortiseval.com/v1";
const headers = { Authorization: `Bearer ${process.env.FORTIS_API_KEY}` };
const AUTO_APPROVE_LIMIT_CENTS = 30000;

app.post(
  "/webhooks/fortis",
  express.raw({ type: "application/json" }), // keep the raw body for the signature
  async (req, res) => {
    const payload = req.body.toString("utf8");

    if (!verifyFortisSignature(payload, req.get("X-Fortis-Signature"), process.env.FORTIS_WHSEC)) {
      return res.sendStatus(400);
    }

    res.sendStatus(200); // acknowledge fast, then do the work

    const event = JSON.parse(payload);
    const object = event.data.object;

    if (event.type === "quote.ready" && object.total_cents <= AUTO_APPROVE_LIMIT_CENTS) {
      await fetch(`${API}/quotes/${object.id}/approve`, { method: "POST", headers });
    }

    if (event.type === "order.completed") {
      const order = await fetch(`${API}/orders/${object.id}`, { headers }).then((r) => r.json());
      const reports = order.documents.filter((d) =>
        ["evaluation", "course_evaluation"].includes(d.document_role),
      );

      for (const report of reports) {
        const { url, file_name } = await fetch(`${API}/documents/${report.id}/download`, { headers })
          .then((r) => r.json());
        await saveToCaseFile(object.custom_reference, file_name, url); // your code
      }
    }
  },
);
```

<Note>
  Deliveries can arrive out of order or more than once. Deduplicate on the
  `X-Fortis-Delivery` header. When you need the current state, fetch the resource
  from the API.
</Note>

## Without webhooks

If you can't receive webhooks, poll instead:

* `GET /v1/quotes/{id}` until `status` is `awaiting_payment`.
* `GET /v1/orders/{id}` until `status` is `completed`.

Poll no more than once a minute. Evaluations take hours to days, depending on
the turnaround you choose.
